diff --git a/api/handlers/api.go b/api/handlers/api.go index 25e3446..509694f 100644 --- a/api/handlers/api.go +++ b/api/handlers/api.go @@ -5,8 +5,6 @@ import ( "io" "net/http" - "github.com/linesmerrill/police-cad-api/api/handlers/search" - "github.com/linesmerrill/police-cad-api/models" "github.com/gorilla/mux" @@ -17,7 +15,7 @@ import ( "github.com/linesmerrill/police-cad-api/databases" ) -// App stores the router and db connection so it can be reused +// App stores the router and db connection, so it can be reused type App struct { Router *mux.Router DB databases.CollectionHelper @@ -31,12 +29,13 @@ func (a *App) New() *mux.Router { u := User{DB: databases.NewUserDatabase(a.dbHelper)} c := Community{DB: databases.NewCommunityDatabase(a.dbHelper)} - n := search.NameSearch{DB: databases.NewCivilianDatabase(a.dbHelper)} civ := Civilian{DB: databases.NewCivilianDatabase(a.dbHelper)} v := Vehicle{DB: databases.NewVehicleDatabase(a.dbHelper)} f := Firearm{DB: databases.NewFirearmDatabase(a.dbHelper)} + l := License{DB: databases.NewLicenseDatabase(a.dbHelper)} e := Ems{DB: databases.NewEmsDatabase(a.dbHelper)} ev := EmsVehicle{DB: databases.NewEmsVehicleDatabase(a.dbHelper)} + w := Warrant{DB: databases.NewWarrantDatabase(a.dbHelper)} call := Call{DB: databases.NewCallDatabase(a.dbHelper)} // healthchex @@ -52,13 +51,25 @@ func (a *App) New() *mux.Router { apiCreate.Handle("/civilian/{civilian_id}", api.Middleware(http.HandlerFunc(civ.CivilianByIDHandler))).Methods("GET") apiCreate.Handle("/civilians", api.Middleware(http.HandlerFunc(civ.CivilianHandler))).Methods("GET") apiCreate.Handle("/civilians/user/{user_id}", api.Middleware(http.HandlerFunc(civ.CiviliansByUserIDHandler))).Methods("GET") - apiCreate.Handle("/name-search", api.Middleware(http.HandlerFunc(n.NameSearchHandler))).Methods("GET") + apiCreate.Handle("/civilians/search", api.Middleware(http.HandlerFunc(civ.CiviliansByNameSearchHandler))).Methods("GET") apiCreate.Handle("/vehicle/{vehicle_id}", api.Middleware(http.HandlerFunc(v.VehicleByIDHandler))).Methods("GET") apiCreate.Handle("/vehicles", api.Middleware(http.HandlerFunc(v.VehicleHandler))).Methods("GET") apiCreate.Handle("/vehicles/user/{user_id}", api.Middleware(http.HandlerFunc(v.VehiclesByUserIDHandler))).Methods("GET") + apiCreate.Handle("/vehicles/registered-owner/{registered_owner_id}", api.Middleware(http.HandlerFunc(v.VehiclesByRegisteredOwnerIDHandler))).Methods("GET") + apiCreate.Handle("/vehicles/search", api.Middleware(http.HandlerFunc(v.VehiclesByPlateSearchHandler))).Methods("GET") apiCreate.Handle("/firearm/{firearm_id}", api.Middleware(http.HandlerFunc(f.FirearmByIDHandler))).Methods("GET") apiCreate.Handle("/firearms", api.Middleware(http.HandlerFunc(f.FirearmHandler))).Methods("GET") apiCreate.Handle("/firearms/user/{user_id}", api.Middleware(http.HandlerFunc(f.FirearmsByUserIDHandler))).Methods("GET") + apiCreate.Handle("/firearms/registered-owner/{registered_owner_id}", api.Middleware(http.HandlerFunc(f.FirearmsByRegisteredOwnerIDHandler))).Methods("GET") + apiCreate.Handle("/license/{license_id}", api.Middleware(http.HandlerFunc(l.LicenseByIDHandler))).Methods("GET") + apiCreate.Handle("/licenses", api.Middleware(http.HandlerFunc(l.LicenseHandler))).Methods("GET") + apiCreate.Handle("/licenses/user/{user_id}", api.Middleware(http.HandlerFunc(l.LicensesByUserIDHandler))).Methods("GET") + apiCreate.Handle("/licenses/owner/{owner_id}", api.Middleware(http.HandlerFunc(l.LicensesByOwnerIDHandler))).Methods("GET") + + apiCreate.Handle("/warrant/{warrant_id}", api.Middleware(http.HandlerFunc(w.WarrantByIDHandler))).Methods("GET") + apiCreate.Handle("/warrants", api.Middleware(http.HandlerFunc(w.WarrantHandler))).Methods("GET") + apiCreate.Handle("/warrants/user/{user_id}", api.Middleware(http.HandlerFunc(w.WarrantsByUserIDHandler))).Methods("GET") + apiCreate.Handle("/ems/{ems_id}", api.Middleware(http.HandlerFunc(e.EmsByIDHandler))).Methods("GET") apiCreate.Handle("/ems", api.Middleware(http.HandlerFunc(e.EmsHandler))).Methods("GET") apiCreate.Handle("/ems/user/{user_id}", api.Middleware(http.HandlerFunc(e.EmsByUserIDHandler))).Methods("GET") diff --git a/api/handlers/call.go b/api/handlers/call.go index 51300a8..98a705c 100644 --- a/api/handlers/call.go +++ b/api/handlers/call.go @@ -3,12 +3,14 @@ package handlers import ( "context" "encoding/json" + "fmt" "net/http" "strconv" "github.com/gorilla/mux" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo/options" "go.uber.org/zap" "github.com/linesmerrill/police-cad-api/config" @@ -23,7 +25,14 @@ type Call struct { // CallHandler returns all calls func (c Call) CallHandler(w http.ResponseWriter, r *http.Request) { - dbResp, err := c.DB.Find(context.TODO(), bson.M{}) + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v, err: %v", Limit|10, err)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) + dbResp, err := c.DB.Find(context.TODO(), bson.D{}, &options.FindOptions{Limit: &limit64, Skip: &skip64}) if err != nil { config.ErrorStatus("failed to get calls", http.StatusNotFound, w, err) return diff --git a/api/handlers/call_test.go b/api/handlers/call_test.go index 7b74819..48acac4 100644 --- a/api/handlers/call_test.go +++ b/api/handlers/call_test.go @@ -239,7 +239,7 @@ func TestCall_CallHandlerJsonMarshalError(t *testing.T) { arg := args.Get(0).(*[]models.Call) *arg = []models.Call{{Details: models.CallDetails{CreatedAt: x}}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "calls").Return(conn) callDatabase := databases.NewCallDatabase(db) @@ -284,7 +284,7 @@ func TestCall_CallHandlerFailedToFindOne(t *testing.T) { client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "calls").Return(conn) callDatabase := databases.NewCallDatabase(db) @@ -333,7 +333,7 @@ func TestCall_CallHandlerSuccess(t *testing.T) { *arg = []models.Call{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "calls").Return(conn) callDatabase := databases.NewCallDatabase(db) @@ -380,7 +380,7 @@ func TestCall_CallHandlerEmptyResponse(t *testing.T) { arg := args.Get(0).(*[]models.Call) *arg = nil }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(cursorHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) db.(*MockDatabaseHelper).On("Collection", "calls").Return(conn) callDatabase := databases.NewCallDatabase(db) @@ -433,7 +433,7 @@ func TestCall_CallsByCommunityIDHandlerJsonMarshalError(t *testing.T) { arg := args.Get(0).(*[]models.Call) *arg = []models.Call{{Details: models.CallDetails{CreatedAt: x}}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "calls").Return(conn) callDatabase := databases.NewCallDatabase(db) @@ -480,7 +480,7 @@ func TestCall_CallsByCommunityIDHandlerFailedToFindOne(t *testing.T) { client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "calls").Return(conn) callDatabase := databases.NewCallDatabase(db) @@ -527,7 +527,7 @@ func TestCall_CallsByCommunityIDHandlerActiveCommunityIDFailedToFindOne(t *testi client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "calls").Return(conn) callDatabase := databases.NewCallDatabase(db) @@ -579,7 +579,7 @@ func TestCall_CallsByCommunityIDHandlerSuccess(t *testing.T) { *arg = []models.Call{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "calls").Return(conn) callDatabase := databases.NewCallDatabase(db) @@ -630,7 +630,7 @@ func TestCall_CallsByCommunityIDHandlerSuccessWithActiveCommunityID(t *testing.T *arg = []models.Call{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "calls").Return(conn) callDatabase := databases.NewCallDatabase(db) @@ -681,7 +681,7 @@ func TestCall_CallsByCommunityIDHandlerSuccessWithNullCommunityID(t *testing.T) *arg = []models.Call{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "calls").Return(conn) callDatabase := databases.NewCallDatabase(db) @@ -731,7 +731,7 @@ func TestCall_CallsByCommunityIDHandlerEmptyResponse(t *testing.T) { arg := args.Get(0).(*[]models.Call) *arg = nil }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(cursorHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) db.(*MockDatabaseHelper).On("Collection", "calls").Return(conn) callDatabase := databases.NewCallDatabase(db) diff --git a/api/handlers/civilian.go b/api/handlers/civilian.go index 0244e8d..ad65860 100644 --- a/api/handlers/civilian.go +++ b/api/handlers/civilian.go @@ -3,11 +3,14 @@ package handlers import ( "context" "encoding/json" + "fmt" "net/http" + "strconv" "github.com/gorilla/mux" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo/options" "go.uber.org/zap" "github.com/linesmerrill/police-cad-api/config" @@ -15,6 +18,11 @@ import ( "github.com/linesmerrill/police-cad-api/models" ) +var ( + // Page denotes the starting Page for pagination results + Page = 0 +) + // Civilian exported for testing purposes type Civilian struct { DB databases.CivilianDatabase @@ -22,7 +30,14 @@ type Civilian struct { // CivilianHandler returns all civilians func (c Civilian) CivilianHandler(w http.ResponseWriter, r *http.Request) { - dbResp, err := c.DB.Find(context.TODO(), bson.M{}) + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v, err: %v", Limit|10, err)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) + dbResp, err := c.DB.Find(context.TODO(), bson.D{}, &options.FindOptions{Limit: &limit64, Skip: &skip64}) if err != nil { config.ErrorStatus("failed to get civilians", http.StatusNotFound, w, err) return @@ -72,6 +87,13 @@ func (c Civilian) CivilianByIDHandler(w http.ResponseWriter, r *http.Request) { func (c Civilian) CiviliansByUserIDHandler(w http.ResponseWriter, r *http.Request) { userID := mux.Vars(r)["user_id"] activeCommunityID := r.URL.Query().Get("active_community_id") + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v", Limit|10)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) zap.S().Debugf("user_id: '%v'", userID) zap.S().Debugf("active_community: '%v'", activeCommunityID) @@ -84,12 +106,12 @@ func (c Civilian) CiviliansByUserIDHandler(w http.ResponseWriter, r *http.Reques // // Likewise, if the user is not in a community, then we will display only the civilians // that are not in a community - var err error + err = nil if activeCommunityID != "" && activeCommunityID != "null" && activeCommunityID != "undefined" { dbResp, err = c.DB.Find(context.TODO(), bson.M{ "civilian.userID": userID, "civilian.activeCommunityID": activeCommunityID, - }) + }, &options.FindOptions{Limit: &limit64, Skip: &skip64}) if err != nil { config.ErrorStatus("failed to get civilians with active community id", http.StatusNotFound, w, err) return @@ -101,7 +123,7 @@ func (c Civilian) CiviliansByUserIDHandler(w http.ResponseWriter, r *http.Reques {"civilian.activeCommunityID": nil}, {"civilian.activeCommunityID": ""}, }, - }) + }, &options.FindOptions{Limit: &limit64, Skip: &skip64}) if err != nil { config.ErrorStatus("failed to get civilians with empty active community id", http.StatusNotFound, w, err) return @@ -121,3 +143,70 @@ func (c Civilian) CiviliansByUserIDHandler(w http.ResponseWriter, r *http.Reques w.WriteHeader(http.StatusOK) w.Write(b) } + +// CiviliansByNameSearchHandler returns paginated list of civilians that match the give name +func (c Civilian) CiviliansByNameSearchHandler(w http.ResponseWriter, r *http.Request) { + firstName := r.URL.Query().Get("first_name") + lastName := r.URL.Query().Get("last_name") + activeCommunityID := r.URL.Query().Get("active_community_id") // optional + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v", Limit|10)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) + + zap.S().Debugf("first_name: '%v', last_name: '%v'", firstName, lastName) + zap.S().Debugf("active_community: '%v'", activeCommunityID) + + var dbResp []models.Civilian + + // If the user is in a community then we want to search for civilians that + // are in that same community. This way each user can have different civilians + // across different communities. + // + // Likewise, if the user is not in a community, then we will display only the civilians + // that are not in a community + err = nil + dbResp, err = c.DB.Find(context.TODO(), bson.M{ + "$text": bson.M{ + "$search": fmt.Sprintf("%s %s", firstName, lastName), + }, + "civilian.activeCommunityID": activeCommunityID, + }, &options.FindOptions{Limit: &limit64, Skip: &skip64}) + if err != nil { + config.ErrorStatus("failed to get civilian name search", http.StatusNotFound, w, err) + return + } + + // Because the frontend requires that the data elements inside models.Civilians exist, if + // len == 0 then we will just return an empty data object + if len(dbResp) == 0 { + dbResp = []models.Civilian{} + } + b, err := json.Marshal(dbResp) + if err != nil { + config.ErrorStatus("failed to marshal response", http.StatusInternalServerError, w, err) + return + } + w.WriteHeader(http.StatusOK) + w.Write(b) +} + +func getPage(Page int, r *http.Request) int { + if r.URL.Query().Get("page") == "" { + zap.S().Warnf("page not set, using default of %v", Page) + } else { + var err error + Page, err = strconv.Atoi(r.URL.Query().Get("page")) + if err != nil { + zap.S().Errorf(fmt.Sprintf("error parsing page number: %v", err)) + } + if Page < 0 { + zap.S().Warnf(fmt.Sprintf("cannot process page number less than 1. Got: %v", Page)) + return 0 + } + } + return Page +} diff --git a/api/handlers/civilian_test.go b/api/handlers/civilian_test.go index 228b393..0ac4be7 100644 --- a/api/handlers/civilian_test.go +++ b/api/handlers/civilian_test.go @@ -239,7 +239,7 @@ func TestCivilian_CivilianHandlerJsonMarshalError(t *testing.T) { arg := args.Get(0).(*[]models.Civilian) *arg = []models.Civilian{{Details: models.CivilianDetails{CreatedAt: x}}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) civilianDatabase := databases.NewCivilianDatabase(db) @@ -284,7 +284,7 @@ func TestCivilian_CivilianHandlerFailedToFindOne(t *testing.T) { client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) civilianDatabase := databases.NewCivilianDatabase(db) @@ -333,7 +333,151 @@ func TestCivilian_CivilianHandlerSuccess(t *testing.T) { *arg = []models.Civilian{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) + + civilianDatabase := databases.NewCivilianDatabase(db) + u := handlers.Civilian{ + DB: civilianDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.CivilianHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testCivilian []models.Civilian + _ = json.Unmarshal(rr.Body.Bytes(), &testCivilian) + + assert.Equal(t, "5fc51f36c72ff10004dca381", testCivilian[0].ID) +} + +func TestCivilian_CivilianHandlerPaginationSuccess(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/civilians?limit=5&page=1", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Civilian) + *arg = []models.Civilian{{ID: "5fc51f36c72ff10004dca381"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) + + civilianDatabase := databases.NewCivilianDatabase(db) + u := handlers.Civilian{ + DB: civilianDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.CivilianHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testCivilian []models.Civilian + _ = json.Unmarshal(rr.Body.Bytes(), &testCivilian) + + assert.Equal(t, "5fc51f36c72ff10004dca381", testCivilian[0].ID) +} + +func TestCivilian_CivilianHandlerPaginationInvalidPageEntry(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/civilians?limit=5&page='1'", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Civilian) + *arg = []models.Civilian{{ID: "5fc51f36c72ff10004dca381"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) + + civilianDatabase := databases.NewCivilianDatabase(db) + u := handlers.Civilian{ + DB: civilianDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.CivilianHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testCivilian []models.Civilian + _ = json.Unmarshal(rr.Body.Bytes(), &testCivilian) + + assert.Equal(t, "5fc51f36c72ff10004dca381", testCivilian[0].ID) +} + +func TestCivilian_CivilianHandlerPaginationInvalidPageEntryLessThan1(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/civilians?limit=5&page=-1", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Civilian) + *arg = []models.Civilian{{ID: "5fc51f36c72ff10004dca381"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) civilianDatabase := databases.NewCivilianDatabase(db) @@ -380,7 +524,7 @@ func TestCivilian_CivilianHandlerEmptyResponse(t *testing.T) { arg := args.Get(0).(*[]models.Civilian) *arg = nil }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(cursorHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) civilianDatabase := databases.NewCivilianDatabase(db) @@ -430,7 +574,7 @@ func TestCivilian_CiviliansByUserIDHandlerJsonMarshalError(t *testing.T) { arg := args.Get(0).(*[]models.Civilian) *arg = []models.Civilian{{Details: models.CivilianDetails{CreatedAt: x}}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) civilianDatabase := databases.NewCivilianDatabase(db) @@ -475,7 +619,7 @@ func TestCivilian_CiviliansByUserIDHandlerFailedToFindOne(t *testing.T) { client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) civilianDatabase := databases.NewCivilianDatabase(db) @@ -520,7 +664,7 @@ func TestCivilian_CiviliansByUserIDHandlerActiveCommunityIDFailedToFindOne(t *te client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) civilianDatabase := databases.NewCivilianDatabase(db) @@ -569,7 +713,7 @@ func TestCivilian_CiviliansByUserIDHandlerSuccess(t *testing.T) { *arg = []models.Civilian{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) civilianDatabase := databases.NewCivilianDatabase(db) @@ -617,7 +761,7 @@ func TestCivilian_CiviliansByUserIDHandlerSuccessWithActiveCommunityID(t *testin *arg = []models.Civilian{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) civilianDatabase := databases.NewCivilianDatabase(db) @@ -665,7 +809,7 @@ func TestCivilian_CiviliansByUserIDHandlerSuccessWithNullCommunityID(t *testing. *arg = []models.Civilian{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) civilianDatabase := databases.NewCivilianDatabase(db) @@ -712,7 +856,7 @@ func TestCivilian_CiviliansByUserIDHandlerEmptyResponse(t *testing.T) { arg := args.Get(0).(*[]models.Civilian) *arg = nil }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(cursorHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) civilianDatabase := databases.NewCivilianDatabase(db) @@ -734,3 +878,380 @@ func TestCivilian_CiviliansByUserIDHandlerEmptyResponse(t *testing.T) { t.Errorf("handler returned unexpected body: \ngot: %v \nwant: %v", rr.Body.String(), expected) } } + +func TestCivilian_CiviliansByNameSearchHandlerJsonMarshalError(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/civilians/search?active_community_id=61c74b7b88e1abdac307bb39&first_name=alessandro&last_name=mills&date_of_birth=1987-03-20", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + x := map[string]interface{}{ + "foo": make(chan int), + } + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Civilian) + *arg = []models.Civilian{{Details: models.CivilianDetails{CreatedAt: x}}} + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) + + civilianDatabase := databases.NewCivilianDatabase(db) + u := handlers.Civilian{ + DB: civilianDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.CiviliansByNameSearchHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusInternalServerError { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to marshal response", Error: "json: unsupported type: chan int"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestCivilian_CiviliansByNameSearchHandlerFailedToFindOne(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/civilians/search?active_community_id=61c74b7b88e1abdac307bb39&first_name=alessandro&last_name=mills&date_of_birth=1987-03-20", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) + + civilianDatabase := databases.NewCivilianDatabase(db) + u := handlers.Civilian{ + DB: civilianDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.CiviliansByNameSearchHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusNotFound { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusNotFound) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get civilian name search", Error: "mongo: no documents in result"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestCivilian_CiviliansByNameSearchHandlerActiveCommunityIDFailedToFindOne(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/civilians/search?active_community_id=61c74b7b88e1abdac307bb39&first_name=alessandro&last_name=mills&date_of_birth=1987-03-20", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) + + civilianDatabase := databases.NewCivilianDatabase(db) + u := handlers.Civilian{ + DB: civilianDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.CiviliansByNameSearchHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusNotFound { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusNotFound) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get civilian name search", Error: "mongo: no documents in result"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestCivilian_CiviliansByNameSearchHandlerSuccess(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/civilians/search?active_community_id=61c74b7b88e1abdac307bb39&first_name=alessandro&last_name=mills&date_of_birth=1987-03-20", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Civilian) + *arg = []models.Civilian{{ID: "5fc51f36c72ff10004dca381"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) + + civilianDatabase := databases.NewCivilianDatabase(db) + u := handlers.Civilian{ + DB: civilianDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.CiviliansByNameSearchHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testCivilian []models.Civilian + _ = json.Unmarshal(rr.Body.Bytes(), &testCivilian) + + assert.Equal(t, "5fc51f36c72ff10004dca381", testCivilian[0].ID) +} + +func TestCivilian_CiviliansByNameSearchHandlerSuccessWithActiveCommunityID(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/civilians/search?active_community_id=61c74b7b88e1abdac307bb39&first_name=alessandro&last_name=mills&date_of_birth=1987-03-20", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Civilian) + *arg = []models.Civilian{{ID: "5fc51f36c72ff10004dca381"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) + + civilianDatabase := databases.NewCivilianDatabase(db) + u := handlers.Civilian{ + DB: civilianDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.CiviliansByNameSearchHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testCivilian []models.Civilian + _ = json.Unmarshal(rr.Body.Bytes(), &testCivilian) + + assert.Equal(t, "5fc51f36c72ff10004dca381", testCivilian[0].ID) +} + +func TestCivilian_CiviliansByNameSearchHandlerSuccessWithNullCommunityID(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/civilians/search?active_community_id=null&first_name=alessandro&last_name=mills&date_of_birth=1987-03-20", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Civilian) + *arg = []models.Civilian{{ID: "5fc51f36c72ff10004dca381"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) + + civilianDatabase := databases.NewCivilianDatabase(db) + u := handlers.Civilian{ + DB: civilianDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.CiviliansByNameSearchHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testCivilian []models.Civilian + _ = json.Unmarshal(rr.Body.Bytes(), &testCivilian) + + assert.Equal(t, "5fc51f36c72ff10004dca381", testCivilian[0].ID) +} + +func TestCivilian_CiviliansByNameSearchHandlerFailedToFindOneWithEmptyCommunityID(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/civilians/search?active_community_id=null&first_name=alessandro&last_name=mills", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) + + civilianDatabase := databases.NewCivilianDatabase(db) + u := handlers.Civilian{ + DB: civilianDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.CiviliansByNameSearchHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusNotFound { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusNotFound) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get civilian name search", Error: "mongo: no documents in result"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestCivilian_CiviliansByNameSearchHandlerEmptyResponse(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/civilians/search?active_community_id=61c74b7b88e1abdac307bb39&first_name=alessandro&last_name=mills&date_of_birth=1987-03-20", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var cursorHelper databases.CursorHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + cursorHelper = &mocks.CursorHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + cursorHelper.(*mocks.CursorHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Civilian) + *arg = nil + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) + db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) + + civilianDatabase := databases.NewCivilianDatabase(db) + u := handlers.Civilian{ + DB: civilianDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.CiviliansByNameSearchHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) + } + + expected := "[]" + if rr.Body.String() != expected { + t.Errorf("handler returned unexpected body: \ngot: %v \nwant: %v", rr.Body.String(), expected) + } +} diff --git a/api/handlers/community_test.go b/api/handlers/community_test.go index b2d0e24..41273ed 100644 --- a/api/handlers/community_test.go +++ b/api/handlers/community_test.go @@ -436,7 +436,7 @@ func TestCommunity_CommunitiesByOwnerIDHandlerJsonMarshalError(t *testing.T) { arg := args.Get(0).(*[]models.Community) *arg = []models.Community{{Details: models.CommunityDetails{ActivePanics: x}}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "communities").Return(conn) communityDatabase := databases.NewCommunityDatabase(db) @@ -482,7 +482,7 @@ func TestCommunity_CommunitiesByOwnerIDHandlerFailedToFindOne(t *testing.T) { client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "communities").Return(conn) communityDatabase := databases.NewCommunityDatabase(db) @@ -532,7 +532,7 @@ func TestCommunity_CommunitiesByOwnerIDHandlerSuccess(t *testing.T) { *arg = []models.Community{{ID: "608cafe595eb9dc05379b7f4"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "communities").Return(conn) communityDatabase := databases.NewCommunityDatabase(db) @@ -580,7 +580,7 @@ func TestUser_CommunitiesByOwnerIDHandlerEmptyResponse(t *testing.T) { arg := args.Get(0).(*[]models.Community) *arg = nil }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(cursorHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) db.(*MockDatabaseHelper).On("Collection", "communities").Return(conn) communityDatabase := databases.NewCommunityDatabase(db) diff --git a/api/handlers/ems.go b/api/handlers/ems.go index b430676..70f33bd 100644 --- a/api/handlers/ems.go +++ b/api/handlers/ems.go @@ -3,11 +3,14 @@ package handlers import ( "context" "encoding/json" + "fmt" "net/http" + "strconv" "github.com/gorilla/mux" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo/options" "go.uber.org/zap" "github.com/linesmerrill/police-cad-api/config" @@ -22,7 +25,14 @@ type Ems struct { // EmsHandler returns all ems func (e Ems) EmsHandler(w http.ResponseWriter, r *http.Request) { - dbResp, err := e.DB.Find(context.TODO(), bson.M{}) + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v, err: %v", Limit|10, err)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) + dbResp, err := e.DB.Find(context.TODO(), bson.D{}, &options.FindOptions{Limit: &limit64, Skip: &skip64}) if err != nil { config.ErrorStatus("failed to get ems", http.StatusNotFound, w, err) return diff --git a/api/handlers/emsVehicle.go b/api/handlers/emsVehicle.go index 686beb9..f978082 100644 --- a/api/handlers/emsVehicle.go +++ b/api/handlers/emsVehicle.go @@ -3,11 +3,14 @@ package handlers import ( "context" "encoding/json" + "fmt" "net/http" + "strconv" "github.com/gorilla/mux" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo/options" "go.uber.org/zap" "github.com/linesmerrill/police-cad-api/config" @@ -22,7 +25,14 @@ type EmsVehicle struct { // EmsVehicleHandler returns all emsVehicles func (v EmsVehicle) EmsVehicleHandler(w http.ResponseWriter, r *http.Request) { - dbResp, err := v.DB.Find(context.TODO(), bson.M{}) + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v, err: %v", Limit|10, err)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) + dbResp, err := v.DB.Find(context.TODO(), bson.D{}, &options.FindOptions{Limit: &limit64, Skip: &skip64}) if err != nil { config.ErrorStatus("failed to get emsVehicles", http.StatusNotFound, w, err) return diff --git a/api/handlers/emsVehicle_test.go b/api/handlers/emsVehicle_test.go index 7621b2d..a32c513 100644 --- a/api/handlers/emsVehicle_test.go +++ b/api/handlers/emsVehicle_test.go @@ -239,7 +239,7 @@ func TestEmsVehicle_EmsVehicleHandlerJsonMarshalError(t *testing.T) { arg := args.Get(0).(*[]models.EmsVehicle) *arg = []models.EmsVehicle{{Details: models.EmsVehicleDetails{CreatedAt: x}}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "emsvehicles").Return(conn) emsVehicleDatabase := databases.NewEmsVehicleDatabase(db) @@ -284,7 +284,7 @@ func TestEmsVehicle_EmsVehicleHandlerFailedToFindOne(t *testing.T) { client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "emsvehicles").Return(conn) emsVehicleDatabase := databases.NewEmsVehicleDatabase(db) @@ -333,7 +333,7 @@ func TestEmsVehicle_EmsVehicleHandlerSuccess(t *testing.T) { *arg = []models.EmsVehicle{{ID: "5fc51f58c72ff10004dca382"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "emsvehicles").Return(conn) emsVehicleDatabase := databases.NewEmsVehicleDatabase(db) @@ -380,7 +380,7 @@ func TestEmsVehicle_EmsVehicleHandlerEmptyResponse(t *testing.T) { arg := args.Get(0).(*[]models.EmsVehicle) *arg = nil }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(cursorHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) db.(*MockDatabaseHelper).On("Collection", "emsvehicles").Return(conn) emsVehicleDatabase := databases.NewEmsVehicleDatabase(db) @@ -430,7 +430,7 @@ func TestEmsVehicle_EmsVehiclesByUserIDHandlerJsonMarshalError(t *testing.T) { arg := args.Get(0).(*[]models.EmsVehicle) *arg = []models.EmsVehicle{{Details: models.EmsVehicleDetails{CreatedAt: x}}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "emsvehicles").Return(conn) emsVehicleDatabase := databases.NewEmsVehicleDatabase(db) @@ -475,7 +475,7 @@ func TestEmsVehicle_EmsVehiclesByUserIDHandlerFailedToFindOne(t *testing.T) { client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "emsvehicles").Return(conn) emsVehicleDatabase := databases.NewEmsVehicleDatabase(db) @@ -520,7 +520,7 @@ func TestEmsVehicle_EmsVehiclesByUserIDHandlerActiveCommunityIDFailedToFindOne(t client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "emsvehicles").Return(conn) emsVehicleDatabase := databases.NewEmsVehicleDatabase(db) @@ -569,7 +569,7 @@ func TestEmsVehicle_EmsVehiclesByUserIDHandlerSuccess(t *testing.T) { *arg = []models.EmsVehicle{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "emsvehicles").Return(conn) emsVehicleDatabase := databases.NewEmsVehicleDatabase(db) @@ -617,7 +617,7 @@ func TestEmsVehicle_EmsVehiclesByUserIDHandlerSuccessWithActiveCommunityID(t *te *arg = []models.EmsVehicle{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "emsvehicles").Return(conn) emsVehicleDatabase := databases.NewEmsVehicleDatabase(db) @@ -665,7 +665,7 @@ func TestEmsVehicle_EmsVehiclesByUserIDHandlerSuccessWithNullCommunityID(t *test *arg = []models.EmsVehicle{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "emsvehicles").Return(conn) emsVehicleDatabase := databases.NewEmsVehicleDatabase(db) @@ -712,7 +712,7 @@ func TestEmsVehicle_EmsVehiclesByUserIDHandlerEmptyResponse(t *testing.T) { arg := args.Get(0).(*[]models.EmsVehicle) *arg = nil }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(cursorHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) db.(*MockDatabaseHelper).On("Collection", "emsvehicles").Return(conn) emsVehicleDatabase := databases.NewEmsVehicleDatabase(db) diff --git a/api/handlers/ems_test.go b/api/handlers/ems_test.go index 4f2f0d3..07a6f29 100644 --- a/api/handlers/ems_test.go +++ b/api/handlers/ems_test.go @@ -239,7 +239,7 @@ func TestEms_EmsHandlerJsonMarshalError(t *testing.T) { arg := args.Get(0).(*[]models.Ems) *arg = []models.Ems{{Details: models.EmsDetails{CreatedAt: x}}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "ems").Return(conn) emsDatabase := databases.NewEmsDatabase(db) @@ -284,7 +284,7 @@ func TestEms_EmsHandlerFailedToFindOne(t *testing.T) { client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "ems").Return(conn) emsDatabase := databases.NewEmsDatabase(db) @@ -333,7 +333,7 @@ func TestEms_EmsHandlerSuccess(t *testing.T) { *arg = []models.Ems{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "ems").Return(conn) emsDatabase := databases.NewEmsDatabase(db) @@ -380,7 +380,7 @@ func TestEms_EmsHandlerEmptyResponse(t *testing.T) { arg := args.Get(0).(*[]models.Ems) *arg = nil }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(cursorHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) db.(*MockDatabaseHelper).On("Collection", "ems").Return(conn) emsDatabase := databases.NewEmsDatabase(db) @@ -430,7 +430,7 @@ func TestEms_EmsByUserIDHandlerJsonMarshalError(t *testing.T) { arg := args.Get(0).(*[]models.Ems) *arg = []models.Ems{{Details: models.EmsDetails{CreatedAt: x}}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "ems").Return(conn) emsDatabase := databases.NewEmsDatabase(db) @@ -475,7 +475,7 @@ func TestEms_EmsByUserIDHandlerFailedToFindOne(t *testing.T) { client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "ems").Return(conn) emsDatabase := databases.NewEmsDatabase(db) @@ -520,7 +520,7 @@ func TestEms_EmsByUserIDHandlerActiveCommunityIDFailedToFindOne(t *testing.T) { client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "ems").Return(conn) emsDatabase := databases.NewEmsDatabase(db) @@ -569,7 +569,7 @@ func TestEms_EmsByUserIDHandlerSuccess(t *testing.T) { *arg = []models.Ems{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "ems").Return(conn) emsDatabase := databases.NewEmsDatabase(db) @@ -617,7 +617,7 @@ func TestEms_EmsByUserIDHandlerSuccessWithActiveCommunityID(t *testing.T) { *arg = []models.Ems{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "ems").Return(conn) emsDatabase := databases.NewEmsDatabase(db) @@ -665,7 +665,7 @@ func TestEms_EmsByUserIDHandlerSuccessWithNullCommunityID(t *testing.T) { *arg = []models.Ems{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "ems").Return(conn) emsDatabase := databases.NewEmsDatabase(db) @@ -712,7 +712,7 @@ func TestEms_EmsByUserIDHandlerEmptyResponse(t *testing.T) { arg := args.Get(0).(*[]models.Ems) *arg = nil }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(cursorHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) db.(*MockDatabaseHelper).On("Collection", "ems").Return(conn) emsDatabase := databases.NewEmsDatabase(db) diff --git a/api/handlers/firearm.go b/api/handlers/firearm.go index 19836ea..097e5c4 100644 --- a/api/handlers/firearm.go +++ b/api/handlers/firearm.go @@ -3,11 +3,14 @@ package handlers import ( "context" "encoding/json" + "fmt" "net/http" + "strconv" "github.com/gorilla/mux" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo/options" "go.uber.org/zap" "github.com/linesmerrill/police-cad-api/config" @@ -20,13 +23,27 @@ type Firearm struct { DB databases.FirearmDatabase } +// FirearmList paginated response with a list of items and next page id +type FirearmList struct { + Items []*models.Firearm `json:"items"` + NextPageID int `json:"next_page_id,omitempty" example:"10"` +} + // FirearmHandler returns all firearms func (v Firearm) FirearmHandler(w http.ResponseWriter, r *http.Request) { - dbResp, err := v.DB.Find(context.TODO(), bson.M{}) + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v, err: %v", Limit|10, err)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) + dbResp, err := v.DB.Find(context.TODO(), bson.D{}, &options.FindOptions{Limit: &limit64, Skip: &skip64}) if err != nil { config.ErrorStatus("failed to get firearms", http.StatusNotFound, w, err) return } + // Because the frontend requires that the data elements inside models.Firearms exist, if // len == 0 then we will just return an empty data object if len(dbResp) == 0 { @@ -72,6 +89,13 @@ func (v Firearm) FirearmByIDHandler(w http.ResponseWriter, r *http.Request) { func (v Firearm) FirearmsByUserIDHandler(w http.ResponseWriter, r *http.Request) { userID := mux.Vars(r)["user_id"] activeCommunityID := r.URL.Query().Get("active_community_id") + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v", Limit|10)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) zap.S().Debugf("user_id: '%v'", userID) zap.S().Debugf("active_community: '%v'", activeCommunityID) @@ -84,12 +108,12 @@ func (v Firearm) FirearmsByUserIDHandler(w http.ResponseWriter, r *http.Request) // // Likewise, if the user is not in a community, then we will display only the firearms // that are not in a community - var err error + err = nil if activeCommunityID != "" && activeCommunityID != "null" && activeCommunityID != "undefined" { dbResp, err = v.DB.Find(context.TODO(), bson.M{ "firearm.userID": userID, "firearm.activeCommunityID": activeCommunityID, - }) + }, &options.FindOptions{Limit: &limit64, Skip: &skip64}) if err != nil { config.ErrorStatus("failed to get firearms with active community id", http.StatusNotFound, w, err) return @@ -101,7 +125,7 @@ func (v Firearm) FirearmsByUserIDHandler(w http.ResponseWriter, r *http.Request) {"firearm.activeCommunityID": nil}, {"firearm.activeCommunityID": ""}, }, - }) + }, &options.FindOptions{Limit: &limit64, Skip: &skip64}) if err != nil { config.ErrorStatus("failed to get firearms with empty active community id", http.StatusNotFound, w, err) return @@ -121,3 +145,47 @@ func (v Firearm) FirearmsByUserIDHandler(w http.ResponseWriter, r *http.Request) w.WriteHeader(http.StatusOK) w.Write(b) } + +// FirearmsByRegisteredOwnerIDHandler returns all firearms that contain the given registeredOwnerID +func (v Firearm) FirearmsByRegisteredOwnerIDHandler(w http.ResponseWriter, r *http.Request) { + registeredOwnerID := mux.Vars(r)["registered_owner_id"] + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v", Limit|10)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) + + zap.S().Debugf("registered_owner_id: '%v'", registeredOwnerID) + + var dbResp []models.Firearm + + // If the user is in a community then we want to search for firearms that + // are in that same community. This way each user can have different firearms + // across different communities. + // + // Likewise, if the user is not in a community, then we will display only the firearms + // that are not in a community + err = nil + dbResp, err = v.DB.Find(context.TODO(), bson.M{ + "firearm.registeredOwnerID": registeredOwnerID, + }, &options.FindOptions{Limit: &limit64, Skip: &skip64}) + if err != nil { + config.ErrorStatus("failed to get firearms with empty registered owner id", http.StatusNotFound, w, err) + return + } + + // Because the frontend requires that the data elements inside models.Firearms exist, if + // len == 0 then we will just return an empty data object + if len(dbResp) == 0 { + dbResp = []models.Firearm{} + } + b, err := json.Marshal(dbResp) + if err != nil { + config.ErrorStatus("failed to marshal response", http.StatusInternalServerError, w, err) + return + } + w.WriteHeader(http.StatusOK) + w.Write(b) +} diff --git a/api/handlers/firearm_test.go b/api/handlers/firearm_test.go index beac672..e7955c1 100644 --- a/api/handlers/firearm_test.go +++ b/api/handlers/firearm_test.go @@ -239,7 +239,7 @@ func TestFirearm_FirearmHandlerJsonMarshalError(t *testing.T) { arg := args.Get(0).(*[]models.Firearm) *arg = []models.Firearm{{Details: models.FirearmDetails{CreatedAt: x}}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "firearms").Return(conn) firearmDatabase := databases.NewFirearmDatabase(db) @@ -284,7 +284,7 @@ func TestFirearm_FirearmHandlerFailedToFindOne(t *testing.T) { client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "firearms").Return(conn) firearmDatabase := databases.NewFirearmDatabase(db) @@ -333,7 +333,7 @@ func TestFirearm_FirearmHandlerSuccess(t *testing.T) { *arg = []models.Firearm{{ID: "5fc51f58c72ff10004dca382"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "firearms").Return(conn) firearmDatabase := databases.NewFirearmDatabase(db) @@ -380,7 +380,7 @@ func TestFirearm_FirearmHandlerEmptyResponse(t *testing.T) { arg := args.Get(0).(*[]models.Firearm) *arg = nil }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(cursorHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) db.(*MockDatabaseHelper).On("Collection", "firearms").Return(conn) firearmDatabase := databases.NewFirearmDatabase(db) @@ -430,7 +430,7 @@ func TestFirearm_FirearmsByUserIDHandlerJsonMarshalError(t *testing.T) { arg := args.Get(0).(*[]models.Firearm) *arg = []models.Firearm{{Details: models.FirearmDetails{CreatedAt: x}}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "firearms").Return(conn) firearmDatabase := databases.NewFirearmDatabase(db) @@ -475,7 +475,7 @@ func TestFirearm_FirearmsByUserIDHandlerFailedToFindOne(t *testing.T) { client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "firearms").Return(conn) firearmDatabase := databases.NewFirearmDatabase(db) @@ -520,7 +520,7 @@ func TestFirearm_FirearmsByUserIDHandlerActiveCommunityIDFailedToFindOne(t *test client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "firearms").Return(conn) firearmDatabase := databases.NewFirearmDatabase(db) @@ -569,7 +569,7 @@ func TestFirearm_FirearmsByUserIDHandlerSuccess(t *testing.T) { *arg = []models.Firearm{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "firearms").Return(conn) firearmDatabase := databases.NewFirearmDatabase(db) @@ -617,7 +617,7 @@ func TestFirearm_FirearmsByUserIDHandlerSuccessWithActiveCommunityID(t *testing. *arg = []models.Firearm{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "firearms").Return(conn) firearmDatabase := databases.NewFirearmDatabase(db) @@ -665,7 +665,7 @@ func TestFirearm_FirearmsByUserIDHandlerSuccessWithNullCommunityID(t *testing.T) *arg = []models.Firearm{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "firearms").Return(conn) firearmDatabase := databases.NewFirearmDatabase(db) @@ -712,7 +712,7 @@ func TestFirearm_FirearmsByUserIDHandlerEmptyResponse(t *testing.T) { arg := args.Get(0).(*[]models.Firearm) *arg = nil }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(cursorHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) db.(*MockDatabaseHelper).On("Collection", "firearms").Return(conn) firearmDatabase := databases.NewFirearmDatabase(db) @@ -734,3 +734,194 @@ func TestFirearm_FirearmsByUserIDHandlerEmptyResponse(t *testing.T) { t.Errorf("handler returned unexpected body: \ngot: %v \nwant: %v", rr.Body.String(), expected) } } + +func TestFirearm_FirearmsByRegisteredOwnerIDHandlerJsonMarshalError(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/firearms/registered-owner/1234", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + x := map[string]interface{}{ + "foo": make(chan int), + } + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Firearm) + *arg = []models.Firearm{{Details: models.FirearmDetails{CreatedAt: x}}} + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "firearms").Return(conn) + + firearmDatabase := databases.NewFirearmDatabase(db) + u := handlers.Firearm{ + DB: firearmDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.FirearmsByRegisteredOwnerIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusInternalServerError { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to marshal response", Error: "json: unsupported type: chan int"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestFirearm_FirearmsByRegisteredOwnerIDHandlerFailedToFindOne(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/firearms/registered-owner/1234", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "firearms").Return(conn) + + firearmDatabase := databases.NewFirearmDatabase(db) + u := handlers.Firearm{ + DB: firearmDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.FirearmsByRegisteredOwnerIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusNotFound { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusNotFound) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get firearms with empty registered owner id", Error: "mongo: no documents in result"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestFirearm_FirearmsByRegisteredOwnerIDHandlerSuccess(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/firearms/registered-owner/61be0ebf22cfea7e7550f00e", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Firearm) + *arg = []models.Firearm{{ID: "5fc51f36c72ff10004dca381"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "firearms").Return(conn) + + firearmDatabase := databases.NewFirearmDatabase(db) + u := handlers.Firearm{ + DB: firearmDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.FirearmsByRegisteredOwnerIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testFirearm []models.Firearm + _ = json.Unmarshal(rr.Body.Bytes(), &testFirearm) + + assert.Equal(t, "5fc51f36c72ff10004dca381", testFirearm[0].ID) +} + +func TestFirearm_FirearmsByRegisteredOwnerIDHandlerEmptyResponse(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/firearms/registered-owner/1234", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var cursorHelper databases.CursorHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + cursorHelper = &mocks.CursorHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + cursorHelper.(*mocks.CursorHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Firearm) + *arg = nil + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) + db.(*MockDatabaseHelper).On("Collection", "firearms").Return(conn) + + firearmDatabase := databases.NewFirearmDatabase(db) + u := handlers.Firearm{ + DB: firearmDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.FirearmsByRegisteredOwnerIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) + } + + expected := "[]" + if rr.Body.String() != expected { + t.Errorf("handler returned unexpected body: \ngot: %v \nwant: %v", rr.Body.String(), expected) + } +} diff --git a/api/handlers/license.go b/api/handlers/license.go new file mode 100644 index 0000000..ea67a8b --- /dev/null +++ b/api/handlers/license.go @@ -0,0 +1,191 @@ +package handlers + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "strconv" + + "github.com/gorilla/mux" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo/options" + "go.uber.org/zap" + + "github.com/linesmerrill/police-cad-api/config" + "github.com/linesmerrill/police-cad-api/databases" + "github.com/linesmerrill/police-cad-api/models" +) + +// License exported for testing purposes +type License struct { + DB databases.LicenseDatabase +} + +// LicenseList paginated response with a list of items and next page id +type LicenseList struct { + Items []*models.License `json:"items"` + NextPageID int `json:"next_page_id,omitempty" example:"10"` +} + +// LicenseHandler returns all licenses +func (v License) LicenseHandler(w http.ResponseWriter, r *http.Request) { + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v, err: %v", Limit|10, err)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) + dbResp, err := v.DB.Find(context.TODO(), bson.D{}, &options.FindOptions{Limit: &limit64, Skip: &skip64}) + if err != nil { + config.ErrorStatus("failed to get licenses", http.StatusNotFound, w, err) + return + } + + // Because the frontend requires that the data elements inside models.Licenses exist, if + // len == 0 then we will just return an empty data object + if len(dbResp) == 0 { + dbResp = []models.License{} + } + b, err := json.Marshal(dbResp) + if err != nil { + config.ErrorStatus("failed to marshal response", http.StatusInternalServerError, w, err) + return + } + w.WriteHeader(http.StatusOK) + w.Write(b) +} + +// LicenseByIDHandler returns a license by ID +func (v License) LicenseByIDHandler(w http.ResponseWriter, r *http.Request) { + civID := mux.Vars(r)["license_id"] + + zap.S().Debugf("license_id: %v", civID) + + cID, err := primitive.ObjectIDFromHex(civID) + if err != nil { + config.ErrorStatus("failed to get objectID from Hex", http.StatusBadRequest, w, err) + return + } + + dbResp, err := v.DB.FindOne(context.Background(), bson.M{"_id": cID}) + if err != nil { + config.ErrorStatus("failed to get license by ID", http.StatusNotFound, w, err) + return + } + + b, err := json.Marshal(dbResp) + if err != nil { + config.ErrorStatus("failed to marshal response", http.StatusInternalServerError, w, err) + return + } + w.WriteHeader(http.StatusOK) + w.Write(b) +} + +// LicensesByUserIDHandler returns all licenses that contain the given userID +func (v License) LicensesByUserIDHandler(w http.ResponseWriter, r *http.Request) { + userID := mux.Vars(r)["user_id"] + activeCommunityID := r.URL.Query().Get("active_community_id") + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v", Limit|10)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) + + zap.S().Debugf("user_id: '%v'", userID) + zap.S().Debugf("active_community: '%v'", activeCommunityID) + + var dbResp []models.License + + // If the user is in a community then we want to search for licenses that + // are in that same community. This way each user can have different licenses + // across different communities. + // + // Likewise, if the user is not in a community, then we will display only the licenses + // that are not in a community + err = nil + if activeCommunityID != "" && activeCommunityID != "null" && activeCommunityID != "undefined" { + dbResp, err = v.DB.Find(context.TODO(), bson.M{ + "license.userID": userID, + "license.activeCommunityID": activeCommunityID, + }, &options.FindOptions{Limit: &limit64, Skip: &skip64}) + if err != nil { + config.ErrorStatus("failed to get licenses with active community id", http.StatusNotFound, w, err) + return + } + } else { + dbResp, err = v.DB.Find(context.TODO(), bson.M{ + "license.userID": userID, + "$or": []bson.M{ + {"license.activeCommunityID": nil}, + {"license.activeCommunityID": ""}, + }, + }, &options.FindOptions{Limit: &limit64, Skip: &skip64}) + if err != nil { + config.ErrorStatus("failed to get licenses with empty active community id", http.StatusNotFound, w, err) + return + } + } + + // Because the frontend requires that the data elements inside models.Licenses exist, if + // len == 0 then we will just return an empty data object + if len(dbResp) == 0 { + dbResp = []models.License{} + } + b, err := json.Marshal(dbResp) + if err != nil { + config.ErrorStatus("failed to marshal response", http.StatusInternalServerError, w, err) + return + } + w.WriteHeader(http.StatusOK) + w.Write(b) +} + +// LicensesByOwnerIDHandler returns all licenses that contain the given OwnerID +func (v License) LicensesByOwnerIDHandler(w http.ResponseWriter, r *http.Request) { + ownerID := mux.Vars(r)["owner_id"] + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v", Limit|10)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) + + zap.S().Debugf("owner_id: '%v'", ownerID) + + var dbResp []models.License + + // If the user is in a community then we want to search for licenses that + // are in that same community. This way each user can have different licenses + // across different communities. + // + // Likewise, if the user is not in a community, then we will display only the licenses + // that are not in a community + err = nil + dbResp, err = v.DB.Find(context.TODO(), bson.M{ + "license.ownerID": ownerID, + }, &options.FindOptions{Limit: &limit64, Skip: &skip64}) + if err != nil { + config.ErrorStatus("failed to get licenses with empty owner id", http.StatusNotFound, w, err) + return + } + + // Because the frontend requires that the data elements inside models.Licenses exist, if + // len == 0 then we will just return an empty data object + if len(dbResp) == 0 { + dbResp = []models.License{} + } + b, err := json.Marshal(dbResp) + if err != nil { + config.ErrorStatus("failed to marshal response", http.StatusInternalServerError, w, err) + return + } + w.WriteHeader(http.StatusOK) + w.Write(b) +} diff --git a/api/handlers/license_test.go b/api/handlers/license_test.go new file mode 100644 index 0000000..f03c622 --- /dev/null +++ b/api/handlers/license_test.go @@ -0,0 +1,927 @@ +package handlers_test + +import ( + "encoding/json" + "errors" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gorilla/mux" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + + "github.com/linesmerrill/police-cad-api/api/handlers" + "github.com/linesmerrill/police-cad-api/databases" + "github.com/linesmerrill/police-cad-api/databases/mocks" + "github.com/linesmerrill/police-cad-api/models" +) + +func TestLicense_LicenseByIDHandler(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/license/1234", nil) + if err != nil { + t.Fatal(err) + } + + req = mux.SetURLVars(req, map[string]string{"license_id": "1234"}) + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mocked-error")) + conn.(*mocks.CollectionHelper).On("FindOne", mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicenseByIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusBadRequest { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get objectID from Hex", Error: "the provided hex string is not a valid ObjectID"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: \ngot: %v \nwant: %v", rr.Body.String(), expected) + } +} + +func TestLicense_LicenseByIDHandlerJsonMarshalError(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/license/5fc51f58c72ff10004dca382", nil) + if err != nil { + t.Fatal(err) + } + + req = mux.SetURLVars(req, map[string]string{"license_id": "5fc51f58c72ff10004dca382"}) + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + x := map[string]interface{}{ + "foo": make(chan int), + } + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(**models.License) + (*arg).Details.CreatedAt = x + + }) + conn.(*mocks.CollectionHelper).On("FindOne", mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicenseByIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusInternalServerError { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to marshal response", Error: "json: unsupported type: chan int"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: \ngot: %v \nwant: %v", rr.Body.String(), expected) + } +} + +func TestLicense_LicenseByIDHandlerFailedToFindOne(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/license/5fc51f58c72ff10004dca999", nil) + if err != nil { + t.Fatal(err) + } + + req = mux.SetURLVars(req, map[string]string{"license_id": "5fc51f58c72ff10004dca999"}) + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) + conn.(*mocks.CollectionHelper).On("FindOne", mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicenseByIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusNotFound { + t.Errorf("handler returned wrong status code:\ngot %v\nwant %v", status, http.StatusBadRequest) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get license by ID", Error: "mongo: no documents in result"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestLicense_LicenseByIDHandlerSuccess(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/license/5fc51f58c72ff10004dca382", nil) + if err != nil { + t.Fatal(err) + } + + req = mux.SetURLVars(req, map[string]string{"license_id": "5fc51f58c72ff10004dca382"}) + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(**models.License) + (*arg).ID = "5fc51f58c72ff10004dca382" + + }) + conn.(*mocks.CollectionHelper).On("FindOne", mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicenseByIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + testLicense := models.License{} + _ = json.Unmarshal(rr.Body.Bytes(), &testLicense) + + assert.Equal(t, "5fc51f58c72ff10004dca382", testLicense.ID) +} + +func TestLicense_LicenseHandlerJsonMarshalError(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/licenses", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + x := map[string]interface{}{ + "foo": make(chan int), + } + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.License) + *arg = []models.License{{Details: models.LicenseDetails{CreatedAt: x}}} + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicenseHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusInternalServerError { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to marshal response", Error: "json: unsupported type: chan int"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestLicense_LicenseHandlerFailedToFindOne(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/licenses", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicenseHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusNotFound { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusNotFound) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get licenses", Error: "mongo: no documents in result"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestLicense_LicenseHandlerSuccess(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/licenses", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.License) + *arg = []models.License{{ID: "5fc51f58c72ff10004dca382"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicenseHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testLicense []models.License + _ = json.Unmarshal(rr.Body.Bytes(), &testLicense) + + assert.Equal(t, "5fc51f58c72ff10004dca382", testLicense[0].ID) +} + +func TestLicense_LicenseHandlerEmptyResponse(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/license", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var cursorHelper databases.CursorHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + cursorHelper = &mocks.CursorHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + cursorHelper.(*mocks.CursorHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.License) + *arg = nil + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicenseHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) + } + + expected := "[]" + if rr.Body.String() != expected { + t.Errorf("handler returned unexpected body: \ngot: %v \nwant: %v", rr.Body.String(), expected) + } +} + +func TestLicense_LicensesByUserIDHandlerJsonMarshalError(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/licenses/user/1234", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + x := map[string]interface{}{ + "foo": make(chan int), + } + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.License) + *arg = []models.License{{Details: models.LicenseDetails{CreatedAt: x}}} + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicensesByUserIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusInternalServerError { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to marshal response", Error: "json: unsupported type: chan int"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestLicense_LicensesByUserIDHandlerFailedToFindOne(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/licenses/user/1234", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicensesByUserIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusNotFound { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusNotFound) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get licenses with empty active community id", Error: "mongo: no documents in result"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestLicense_LicensesByUserIDHandlerActiveCommunityIDFailedToFindOne(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/licenses/user/1234?active_community_id=1234", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicensesByUserIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusNotFound { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusNotFound) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get licenses with active community id", Error: "mongo: no documents in result"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestLicense_LicensesByUserIDHandlerSuccess(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/licenses/user/61be0ebf22cfea7e7550f00e", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.License) + *arg = []models.License{{ID: "5fc51f36c72ff10004dca381"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicensesByUserIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testLicense []models.License + _ = json.Unmarshal(rr.Body.Bytes(), &testLicense) + + assert.Equal(t, "5fc51f36c72ff10004dca381", testLicense[0].ID) +} + +func TestLicense_LicensesByUserIDHandlerSuccessWithActiveCommunityID(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/licenses/user/61be0ebf22cfea7e7550f00e?active_community_id=61c74b7b88e1abdac307bb39", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.License) + *arg = []models.License{{ID: "5fc51f36c72ff10004dca381"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicensesByUserIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testLicense []models.License + _ = json.Unmarshal(rr.Body.Bytes(), &testLicense) + + assert.Equal(t, "5fc51f36c72ff10004dca381", testLicense[0].ID) +} + +func TestLicense_LicensesByUserIDHandlerSuccessWithNullCommunityID(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/licenses/user/61be0ebf22cfea7e7550f00e?active_community_id=null", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.License) + *arg = []models.License{{ID: "5fc51f36c72ff10004dca381"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicensesByUserIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testLicense []models.License + _ = json.Unmarshal(rr.Body.Bytes(), &testLicense) + + assert.Equal(t, "5fc51f36c72ff10004dca381", testLicense[0].ID) +} + +func TestLicense_LicensesByUserIDHandlerEmptyResponse(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/licenses/user/1234", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var cursorHelper databases.CursorHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + cursorHelper = &mocks.CursorHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + cursorHelper.(*mocks.CursorHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.License) + *arg = nil + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicensesByUserIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) + } + + expected := "[]" + if rr.Body.String() != expected { + t.Errorf("handler returned unexpected body: \ngot: %v \nwant: %v", rr.Body.String(), expected) + } +} + +func TestLicense_LicensesByOwnerIDHandlerJsonMarshalError(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/licenses/owner/1234", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + x := map[string]interface{}{ + "foo": make(chan int), + } + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.License) + *arg = []models.License{{Details: models.LicenseDetails{CreatedAt: x}}} + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicensesByOwnerIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusInternalServerError { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to marshal response", Error: "json: unsupported type: chan int"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestLicense_LicensesByOwnerIDHandlerFailedToFindOne(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/licenses/owner/1234", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicensesByOwnerIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusNotFound { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusNotFound) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get licenses with empty owner id", Error: "mongo: no documents in result"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestLicense_LicensesByOwnerIDHandlerSuccess(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/licenses/owner/61be0ebf22cfea7e7550f00e", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.License) + *arg = []models.License{{ID: "5fc51f36c72ff10004dca381"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicensesByOwnerIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testLicense []models.License + _ = json.Unmarshal(rr.Body.Bytes(), &testLicense) + + assert.Equal(t, "5fc51f36c72ff10004dca381", testLicense[0].ID) +} + +func TestLicense_LicensesByOwnerIDHandlerEmptyResponse(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/licenses/owner/1234", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var cursorHelper databases.CursorHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + cursorHelper = &mocks.CursorHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + cursorHelper.(*mocks.CursorHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.License) + *arg = nil + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) + db.(*MockDatabaseHelper).On("Collection", "licenses").Return(conn) + + licenseDatabase := databases.NewLicenseDatabase(db) + u := handlers.License{ + DB: licenseDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.LicensesByOwnerIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) + } + + expected := "[]" + if rr.Body.String() != expected { + t.Errorf("handler returned unexpected body: \ngot: %v \nwant: %v", rr.Body.String(), expected) + } +} diff --git a/api/handlers/search/name.go b/api/handlers/search/name.go deleted file mode 100644 index 621438f..0000000 --- a/api/handlers/search/name.go +++ /dev/null @@ -1,66 +0,0 @@ -package search - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - - "go.mongodb.org/mongo-driver/bson" - "go.uber.org/zap" - - "github.com/linesmerrill/police-cad-api/config" - "github.com/linesmerrill/police-cad-api/databases" - "github.com/linesmerrill/police-cad-api/models" -) - -// NameSearch holds the database object -type NameSearch struct { - DB databases.CivilianDatabase -} - -// NameSearchHandler contains the logic to handle basic name searches given -// a first name, last name, date-of-birth and communityID. This is the main -// search route for trying to locate a name in the database. -func (n NameSearch) NameSearchHandler(w http.ResponseWriter, r *http.Request) { - - firstName := r.URL.Query().Get("first_name") - lastName := r.URL.Query().Get("last_name") - dob := r.URL.Query().Get("dob") - communityID := r.URL.Query().Get("community_id") - - zap.S().Debugf("first_name: %v, last_name: %v, dob: %v, community_id: %v", firstName, lastName, dob, communityID) - - dbResp, err := n.DB.Find(context.TODO(), bson.M{ - "$and": []bson.M{ - bson.M{ - "$text": bson.M{ - "$search": fmt.Sprintf("%v %v", firstName, lastName), - }, - }, - bson.M{ - "civilian.birthday": dob, - }, - bson.M{"$or": []bson.M{ - bson.M{"civilian.activeCommunityID": ""}, - bson.M{"civilian.activeCommunityID": nil}, - }}, - }, - }) - if err != nil { - config.ErrorStatus("failed to get name", http.StatusNotFound, w, err) - return - } - // Because the frontend requires that the data elements inside models.User exist, if - // len == 0 then we will just return an empty data object - if len(dbResp) == 0 { - dbResp = []models.Civilian{} - } - b, err := json.Marshal(dbResp) - if err != nil { - config.ErrorStatus("failed to marshal response", http.StatusInternalServerError, w, err) - return - } - w.WriteHeader(http.StatusOK) - w.Write(b) -} diff --git a/api/handlers/search/name_test.go b/api/handlers/search/name_test.go deleted file mode 100644 index b9617f6..0000000 --- a/api/handlers/search/name_test.go +++ /dev/null @@ -1,244 +0,0 @@ -package search_test - -import ( - "encoding/json" - "errors" - "net/http" - "net/http/httptest" - "testing" - - "github.com/linesmerrill/police-cad-api/api/handlers/search" - - "github.com/linesmerrill/police-cad-api/databases" - "github.com/linesmerrill/police-cad-api/databases/mocks" - "github.com/linesmerrill/police-cad-api/models" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -type MockDatabaseHelper struct { - mock.Mock -} - -// Client provides a mock function. -func (_m *MockDatabaseHelper) Client() databases.ClientHelper { - ret := _m.Called() - - var r0 databases.ClientHelper - if rf, ok := ret.Get(0).(func() databases.ClientHelper); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(databases.ClientHelper) - } - } - - return r0 -} - -// Collection provides a mock function. -func (_m *MockDatabaseHelper) Collection(name string) databases.CollectionHelper { - ret := _m.Called(name) - - var r0 databases.CollectionHelper - if rf, ok := ret.Get(0).(func(string) databases.CollectionHelper); ok { - r0 = rf(name) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(databases.CollectionHelper) - } - } - - return r0 -} - -func TestName_NameSearchHandlerJsonMarshalError(t *testing.T) { - req, err := http.NewRequest("GET", "/api/v1/name-search?first_name=John&last_name=Yelp", nil) - if err != nil { - t.Fatal(err) - } - req.Header.Set("Authorization", "Bearer abc123") - - var db databases.DatabaseHelper - var client databases.ClientHelper - var conn databases.CollectionHelper - var singleResultHelper databases.SingleResultHelper - - db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} - client = &mocks.ClientHelper{} - conn = &mocks.CollectionHelper{} - singleResultHelper = &mocks.SingleResultHelper{} - - x := map[string]interface{}{ - "foo": make(chan int), - } - - client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) - db.(*MockDatabaseHelper).On("Client").Return(client) - singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { - arg := args.Get(0).(*[]models.Civilian) - *arg = []models.Civilian{{Details: models.CivilianDetails{CreatedAt: x}}} - }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) - db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) - - civilianDatabase := databases.NewCivilianDatabase(db) - u := search.NameSearch{ - DB: civilianDatabase, - } - - rr := httptest.NewRecorder() - handler := http.HandlerFunc(u.NameSearchHandler) - - handler.ServeHTTP(rr, req) - - if status := rr.Code; status != http.StatusInternalServerError { - t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) - } - - expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to marshal response", Error: "json: unsupported type: chan int"}} - b, _ := json.Marshal(expected) - if rr.Body.String() != string(b) { - t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) - } -} - -func TestName_NameSearchHandlerFailedToFindOne(t *testing.T) { - req, err := http.NewRequest("GET", "/api/v1/name-search?first_name=Does-not-exist&last_name=Does-not-exist", nil) - if err != nil { - t.Fatal(err) - } - - req.Header.Set("Authorization", "Bearer abc123") - - var db databases.DatabaseHelper - var client databases.ClientHelper - var conn databases.CollectionHelper - var singleResultHelper databases.SingleResultHelper - - db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} - client = &mocks.ClientHelper{} - conn = &mocks.CollectionHelper{} - singleResultHelper = &mocks.SingleResultHelper{} - - client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) - db.(*MockDatabaseHelper).On("Client").Return(client) - singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) - db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) - - civilianDatabase := databases.NewCivilianDatabase(db) - u := search.NameSearch{ - DB: civilianDatabase, - } - - rr := httptest.NewRecorder() - handler := http.HandlerFunc(u.NameSearchHandler) - - handler.ServeHTTP(rr, req) - - if status := rr.Code; status != http.StatusNotFound { - t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusNotFound) - } - - expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get name", Error: "mongo: no documents in result"}} - b, _ := json.Marshal(expected) - if rr.Body.String() != string(b) { - t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) - } -} - -func TestName_NameSearchHandlerSuccess(t *testing.T) { - req, err := http.NewRequest("GET", "/api/v1/name-search?first_name=John&last_name=Yelp", nil) - if err != nil { - t.Fatal(err) - } - - req.Header.Set("Authorization", "Bearer abc123") - - var db databases.DatabaseHelper - var client databases.ClientHelper - var conn databases.CollectionHelper - var singleResultHelper databases.SingleResultHelper - - db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} - client = &mocks.ClientHelper{} - conn = &mocks.CollectionHelper{} - singleResultHelper = &mocks.SingleResultHelper{} - - client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) - db.(*MockDatabaseHelper).On("Client").Return(client) - singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { - arg := args.Get(0).(*[]models.Civilian) - *arg = []models.Civilian{{ID: "5fc51f58c72ff10004dca382"}} - - }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) - db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) - - civilianDatabase := databases.NewCivilianDatabase(db) - u := search.NameSearch{ - DB: civilianDatabase, - } - - rr := httptest.NewRecorder() - handler := http.HandlerFunc(u.NameSearchHandler) - - handler.ServeHTTP(rr, req) - - if status := rr.Code; status != http.StatusOK { - t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) - } - - var testCivilian []models.Civilian - _ = json.Unmarshal(rr.Body.Bytes(), &testCivilian) - - assert.Equal(t, "5fc51f58c72ff10004dca382", testCivilian[0].ID) -} - -func TestName_NameSearchHandlerEmptyResponse(t *testing.T) { - req, err := http.NewRequest("GET", "/api/v1/name-search?first_name=Empty&last_name=Response", nil) - if err != nil { - t.Fatal(err) - } - - req.Header.Set("Authorization", "Bearer abc123") - - var db databases.DatabaseHelper - var client databases.ClientHelper - var conn databases.CollectionHelper - var cursorHelper databases.CursorHelper - - db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} - client = &mocks.ClientHelper{} - conn = &mocks.CollectionHelper{} - cursorHelper = &mocks.CursorHelper{} - - client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) - db.(*MockDatabaseHelper).On("Client").Return(client) - cursorHelper.(*mocks.CursorHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { - arg := args.Get(0).(*[]models.Civilian) - *arg = nil - }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(cursorHelper) - db.(*MockDatabaseHelper).On("Collection", "civilians").Return(conn) - - civilianDatabase := databases.NewCivilianDatabase(db) - u := search.NameSearch{ - DB: civilianDatabase, - } - - rr := httptest.NewRecorder() - handler := http.HandlerFunc(u.NameSearchHandler) - - handler.ServeHTTP(rr, req) - - if status := rr.Code; status != http.StatusOK { - t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) - } - - expected := "[]" - if rr.Body.String() != expected { - t.Errorf("handler returned unexpected body: \ngot: %v \nwant: %v", rr.Body.String(), expected) - } -} diff --git a/api/handlers/user_test.go b/api/handlers/user_test.go index 9f55325..6b86097 100644 --- a/api/handlers/user_test.go +++ b/api/handlers/user_test.go @@ -266,7 +266,7 @@ func TestUser_UsersFindAllHandlerInvalidID(t *testing.T) { client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mocked-error")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "users").Return(conn) userDatabase := databases.NewUserDatabase(db) @@ -319,7 +319,7 @@ func TestUser_UsersFindAllHandlerJsonMarshalError(t *testing.T) { arg := args.Get(0).(*[]models.User) (*arg) = []models.User{{Details: models.UserDetails{CreatedAt: x}}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "users").Return(conn) userDatabase := databases.NewUserDatabase(db) @@ -365,7 +365,7 @@ func TestUser_UsersFindAllHandlerFailedToFindOne(t *testing.T) { client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "users").Return(conn) userDatabase := databases.NewUserDatabase(db) @@ -414,7 +414,7 @@ func TestUser_UsersFindAllHandlerSuccess(t *testing.T) { arg := args.Get(0).(*[]models.User) (*arg) = []models.User{{ID: "608cafd695eb9dc05379b7f3"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(cursorHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) db.(*MockDatabaseHelper).On("Collection", "users").Return(conn) userDatabase := databases.NewUserDatabase(db) @@ -462,7 +462,7 @@ func TestUser_UsersFindAllHandlerEmptyResponse(t *testing.T) { arg := args.Get(0).(*[]models.User) (*arg) = nil }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(cursorHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) db.(*MockDatabaseHelper).On("Collection", "users").Return(conn) userDatabase := databases.NewUserDatabase(db) diff --git a/api/handlers/vehicle.go b/api/handlers/vehicle.go index 11e33b7..efa2a12 100644 --- a/api/handlers/vehicle.go +++ b/api/handlers/vehicle.go @@ -3,11 +3,14 @@ package handlers import ( "context" "encoding/json" + "fmt" "net/http" + "strconv" "github.com/gorilla/mux" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo/options" "go.uber.org/zap" "github.com/linesmerrill/police-cad-api/config" @@ -22,7 +25,14 @@ type Vehicle struct { // VehicleHandler returns all vehicles func (v Vehicle) VehicleHandler(w http.ResponseWriter, r *http.Request) { - dbResp, err := v.DB.Find(context.TODO(), bson.M{}) + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v, err: %v", Limit|10, err)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) + dbResp, err := v.DB.Find(context.TODO(), bson.D{}, &options.FindOptions{Limit: &limit64, Skip: &skip64}) if err != nil { config.ErrorStatus("failed to get vehicles", http.StatusNotFound, w, err) return @@ -72,6 +82,13 @@ func (v Vehicle) VehicleByIDHandler(w http.ResponseWriter, r *http.Request) { func (v Vehicle) VehiclesByUserIDHandler(w http.ResponseWriter, r *http.Request) { userID := mux.Vars(r)["user_id"] activeCommunityID := r.URL.Query().Get("active_community_id") + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v", Limit|10)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) zap.S().Debugf("user_id: '%v'", userID) zap.S().Debugf("active_community: '%v'", activeCommunityID) @@ -84,12 +101,12 @@ func (v Vehicle) VehiclesByUserIDHandler(w http.ResponseWriter, r *http.Request) // // Likewise, if the user is not in a community, then we will display only the vehicles // that are not in a community - var err error + err = nil if activeCommunityID != "" && activeCommunityID != "null" && activeCommunityID != "undefined" { dbResp, err = v.DB.Find(context.TODO(), bson.M{ "vehicle.userID": userID, "vehicle.activeCommunityID": activeCommunityID, - }) + }, &options.FindOptions{Limit: &limit64, Skip: &skip64}) if err != nil { config.ErrorStatus("failed to get vehicles with active community id", http.StatusNotFound, w, err) return @@ -101,7 +118,7 @@ func (v Vehicle) VehiclesByUserIDHandler(w http.ResponseWriter, r *http.Request) {"vehicle.activeCommunityID": nil}, {"vehicle.activeCommunityID": ""}, }, - }) + }, &options.FindOptions{Limit: &limit64, Skip: &skip64}) if err != nil { config.ErrorStatus("failed to get vehicles with empty active community id", http.StatusNotFound, w, err) return @@ -121,3 +138,104 @@ func (v Vehicle) VehiclesByUserIDHandler(w http.ResponseWriter, r *http.Request) w.WriteHeader(http.StatusOK) w.Write(b) } + +// VehiclesByRegisteredOwnerIDHandler returns all vehicles that contain the given registeredOwnerID +func (v Vehicle) VehiclesByRegisteredOwnerIDHandler(w http.ResponseWriter, r *http.Request) { + registeredOwnerID := mux.Vars(r)["registered_owner_id"] + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v", Limit|10)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) + + zap.S().Debugf("registered_owner_id: '%v'", registeredOwnerID) + + var dbResp []models.Vehicle + + err = nil + dbResp, err = v.DB.Find(context.TODO(), bson.M{ + "vehicle.registeredOwnerID": registeredOwnerID, + }, &options.FindOptions{Limit: &limit64, Skip: &skip64}) + if err != nil { + config.ErrorStatus("failed to get vehicles by registered owner id", http.StatusNotFound, w, err) + return + } + + // Because the frontend requires that the data elements inside models.Vehicles exist, if + // len == 0 then we will just return an empty data object + if len(dbResp) == 0 { + dbResp = []models.Vehicle{} + } + b, err := json.Marshal(dbResp) + if err != nil { + config.ErrorStatus("failed to marshal response", http.StatusInternalServerError, w, err) + return + } + w.WriteHeader(http.StatusOK) + w.Write(b) +} + +// VehiclesByPlateSearchHandler returns paginated list of vehicles that match the give plate +func (v Vehicle) VehiclesByPlateSearchHandler(w http.ResponseWriter, r *http.Request) { + plate := r.URL.Query().Get("plate") + activeCommunityID := r.URL.Query().Get("active_community_id") // optional + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v", Limit|10)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) + + zap.S().Debugf("plate: '%v'", plate) + zap.S().Debugf("active_community: '%v'", activeCommunityID) + + var dbResp []models.Vehicle + + // If the user is in a community then we want to search for vehicles that + // are in that same community. This way each user can have different vehicles + // across different communities. + // + // Likewise, if the user is not in a community, then we will display only the vehicles + // that are not in a community + err = nil + if activeCommunityID != "" && activeCommunityID != "null" && activeCommunityID != "undefined" { + dbResp, err = v.DB.Find(context.TODO(), bson.M{ + "$text": bson.M{ + "$search": fmt.Sprintf("%s", plate), + }, + "vehicle.activeCommunityID": activeCommunityID, + }, &options.FindOptions{Limit: &limit64, Skip: &skip64}) + if err != nil { + config.ErrorStatus("failed to get vehicle plate search with active community id", http.StatusNotFound, w, err) + return + } + } else { + dbResp, err = v.DB.Find(context.TODO(), bson.M{ + "vehicle.plate": plate, + "$or": []bson.M{ + {"vehicle.activeCommunityID": nil}, + {"vehicle.activeCommunityID": ""}, + }, + }, &options.FindOptions{Limit: &limit64, Skip: &skip64}) + if err != nil { + config.ErrorStatus("failed to get vehicle plate search with empty active community id", http.StatusNotFound, w, err) + return + } + } + + // Because the frontend requires that the data elements inside models.Vehicles exist, if + // len == 0 then we will just return an empty data object + if len(dbResp) == 0 { + dbResp = []models.Vehicle{} + } + b, err := json.Marshal(dbResp) + if err != nil { + config.ErrorStatus("failed to marshal response", http.StatusInternalServerError, w, err) + return + } + w.WriteHeader(http.StatusOK) + w.Write(b) +} diff --git a/api/handlers/vehicle_test.go b/api/handlers/vehicle_test.go index 35b492e..17d49c7 100644 --- a/api/handlers/vehicle_test.go +++ b/api/handlers/vehicle_test.go @@ -239,7 +239,7 @@ func TestVehicle_VehicleHandlerJsonMarshalError(t *testing.T) { arg := args.Get(0).(*[]models.Vehicle) *arg = []models.Vehicle{{Details: models.VehicleDetails{CreatedAt: x}}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) vehicleDatabase := databases.NewVehicleDatabase(db) @@ -284,7 +284,7 @@ func TestVehicle_VehicleHandlerFailedToFindOne(t *testing.T) { client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) vehicleDatabase := databases.NewVehicleDatabase(db) @@ -333,7 +333,7 @@ func TestVehicle_VehicleHandlerSuccess(t *testing.T) { *arg = []models.Vehicle{{ID: "5fc51f58c72ff10004dca382"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) vehicleDatabase := databases.NewVehicleDatabase(db) @@ -380,7 +380,7 @@ func TestVehicle_VehicleHandlerEmptyResponse(t *testing.T) { arg := args.Get(0).(*[]models.Vehicle) *arg = nil }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(cursorHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) vehicleDatabase := databases.NewVehicleDatabase(db) @@ -430,7 +430,7 @@ func TestVehicle_VehiclesByUserIDHandlerJsonMarshalError(t *testing.T) { arg := args.Get(0).(*[]models.Vehicle) *arg = []models.Vehicle{{Details: models.VehicleDetails{CreatedAt: x}}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) vehicleDatabase := databases.NewVehicleDatabase(db) @@ -475,7 +475,7 @@ func TestVehicle_VehiclesByUserIDHandlerFailedToFindOne(t *testing.T) { client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) vehicleDatabase := databases.NewVehicleDatabase(db) @@ -520,7 +520,7 @@ func TestVehicle_VehiclesByUserIDHandlerActiveCommunityIDFailedToFindOne(t *test client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) db.(*MockDatabaseHelper).On("Client").Return(client) singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) vehicleDatabase := databases.NewVehicleDatabase(db) @@ -569,7 +569,7 @@ func TestVehicle_VehiclesByUserIDHandlerSuccess(t *testing.T) { *arg = []models.Vehicle{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) vehicleDatabase := databases.NewVehicleDatabase(db) @@ -617,7 +617,7 @@ func TestVehicle_VehiclesByUserIDHandlerSuccessWithActiveCommunityID(t *testing. *arg = []models.Vehicle{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) vehicleDatabase := databases.NewVehicleDatabase(db) @@ -665,7 +665,7 @@ func TestVehicle_VehiclesByUserIDHandlerSuccessWithNullCommunityID(t *testing.T) *arg = []models.Vehicle{{ID: "5fc51f36c72ff10004dca381"}} }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(singleResultHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) vehicleDatabase := databases.NewVehicleDatabase(db) @@ -712,7 +712,7 @@ func TestVehicle_VehiclesByUserIDHandlerEmptyResponse(t *testing.T) { arg := args.Get(0).(*[]models.Vehicle) *arg = nil }) - conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything).Return(cursorHelper) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) vehicleDatabase := databases.NewVehicleDatabase(db) @@ -734,3 +734,430 @@ func TestVehicle_VehiclesByUserIDHandlerEmptyResponse(t *testing.T) { t.Errorf("handler returned unexpected body: \ngot: %v \nwant: %v", rr.Body.String(), expected) } } + +func TestVehicle_VehiclesByRegisteredOwnerIDHandlerJsonMarshalError(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/vehicles/registered-owner/1234", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + x := map[string]interface{}{ + "foo": make(chan int), + } + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Vehicle) + *arg = []models.Vehicle{{Details: models.VehicleDetails{CreatedAt: x}}} + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) + + vehicleDatabase := databases.NewVehicleDatabase(db) + u := handlers.Vehicle{ + DB: vehicleDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.VehiclesByRegisteredOwnerIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusInternalServerError { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to marshal response", Error: "json: unsupported type: chan int"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestVehicle_VehiclesByRegisteredOwnerIDHandlerFailedToFindOne(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/vehicles/registered-owner/1234", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) + + vehicleDatabase := databases.NewVehicleDatabase(db) + u := handlers.Vehicle{ + DB: vehicleDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.VehiclesByRegisteredOwnerIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusNotFound { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusNotFound) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get vehicles by registered owner id", Error: "mongo: no documents in result"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestVehicle_VehiclesByRegisteredOwnerIDHandlerSuccess(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/vehicles/registered-owner/61be0ebf22cfea7e7550f00e", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Vehicle) + *arg = []models.Vehicle{{ID: "5fc51f36c72ff10004dca381"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) + + vehicleDatabase := databases.NewVehicleDatabase(db) + u := handlers.Vehicle{ + DB: vehicleDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.VehiclesByRegisteredOwnerIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testVehicle []models.Vehicle + _ = json.Unmarshal(rr.Body.Bytes(), &testVehicle) + + assert.Equal(t, "5fc51f36c72ff10004dca381", testVehicle[0].ID) +} + +func TestVehicle_VehiclesByRegisteredOwnerIDHandlerEmptyResponse(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/vehicles/registered-owner/1234", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var cursorHelper databases.CursorHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + cursorHelper = &mocks.CursorHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + cursorHelper.(*mocks.CursorHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Vehicle) + *arg = nil + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) + db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) + + vehicleDatabase := databases.NewVehicleDatabase(db) + u := handlers.Vehicle{ + DB: vehicleDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.VehiclesByRegisteredOwnerIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) + } + + expected := "[]" + if rr.Body.String() != expected { + t.Errorf("handler returned unexpected body: \ngot: %v \nwant: %v", rr.Body.String(), expected) + } +} + +func TestVehicle_VehiclesByPlateSearchHandlerJsonMarshalError(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/vehicles/search", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + x := map[string]interface{}{ + "foo": make(chan int), + } + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Vehicle) + *arg = []models.Vehicle{{Details: models.VehicleDetails{CreatedAt: x}}} + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) + + vehicleDatabase := databases.NewVehicleDatabase(db) + u := handlers.Vehicle{ + DB: vehicleDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.VehiclesByPlateSearchHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusInternalServerError { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to marshal response", Error: "json: unsupported type: chan int"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestVehicle_VehiclesByPlateSearchHandlerFailedToFindOne(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/vehicles/search?active_community_id=61c74b7b88e1abdac307bb39", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("failed to get vehicle plate search with empty active community id")) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) + + vehicleDatabase := databases.NewVehicleDatabase(db) + u := handlers.Vehicle{ + DB: vehicleDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.VehiclesByPlateSearchHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusNotFound { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusNotFound) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get vehicle plate search with active community id", Error: "failed to get vehicle plate search with empty active community id"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestVehicle_VehiclesByPlateSearchHandlerFailedToFindOneWithEmptyCommunityID(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/vehicles/search", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("failed to get vehicle plate search with empty active community id")) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) + + vehicleDatabase := databases.NewVehicleDatabase(db) + u := handlers.Vehicle{ + DB: vehicleDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.VehiclesByPlateSearchHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusNotFound { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusNotFound) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get vehicle plate search with empty active community id", Error: "failed to get vehicle plate search with empty active community id"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestVehicle_VehiclesByPlateSearchHandlerSuccess(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/vehicles/search?active_community_id=61be0ebf22cfea7e7550f00e", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Vehicle) + *arg = []models.Vehicle{{ID: "5fc51f36c72ff10004dca381"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) + + vehicleDatabase := databases.NewVehicleDatabase(db) + u := handlers.Vehicle{ + DB: vehicleDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.VehiclesByPlateSearchHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testVehicle []models.Vehicle + _ = json.Unmarshal(rr.Body.Bytes(), &testVehicle) + + assert.Equal(t, "5fc51f36c72ff10004dca381", testVehicle[0].ID) +} + +func TestVehicle_VehiclesByPlateSearchHandlerEmptyResponse(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/vehicles/search", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var cursorHelper databases.CursorHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + cursorHelper = &mocks.CursorHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + cursorHelper.(*mocks.CursorHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Vehicle) + *arg = nil + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) + db.(*MockDatabaseHelper).On("Collection", "vehicles").Return(conn) + + vehicleDatabase := databases.NewVehicleDatabase(db) + u := handlers.Vehicle{ + DB: vehicleDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.VehiclesByPlateSearchHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) + } + + expected := "[]" + if rr.Body.String() != expected { + t.Errorf("handler returned unexpected body: \ngot: %v \nwant: %v", rr.Body.String(), expected) + } +} diff --git a/api/handlers/warrant.go b/api/handlers/warrant.go new file mode 100644 index 0000000..ac99535 --- /dev/null +++ b/api/handlers/warrant.go @@ -0,0 +1,139 @@ +package handlers + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "strconv" + + "github.com/gorilla/mux" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo/options" + "go.uber.org/zap" + + "github.com/linesmerrill/police-cad-api/config" + "github.com/linesmerrill/police-cad-api/databases" + "github.com/linesmerrill/police-cad-api/models" +) + +// Warrant exported for testing purposes +type Warrant struct { + DB databases.WarrantDatabase +} + +// WarrantList paginated response with a list of items and next page id +type WarrantList struct { + Items []*models.Warrant `json:"items"` + NextPageID int `json:"next_page_id,omitempty" example:"10"` +} + +// WarrantHandler returns all warrants +func (v Warrant) WarrantHandler(w http.ResponseWriter, r *http.Request) { + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v, err: %v", Limit|10, err)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) + dbResp, err := v.DB.Find(context.TODO(), bson.D{}, &options.FindOptions{Limit: &limit64, Skip: &skip64}) + if err != nil { + config.ErrorStatus("failed to get warrants", http.StatusNotFound, w, err) + return + } + + // Because the frontend requires that the data elements inside models.Warrants exist, if + // len == 0 then we will just return an empty data object + if len(dbResp) == 0 { + dbResp = []models.Warrant{} + } + b, err := json.Marshal(dbResp) + if err != nil { + config.ErrorStatus("failed to marshal response", http.StatusInternalServerError, w, err) + return + } + w.WriteHeader(http.StatusOK) + w.Write(b) +} + +// WarrantByIDHandler returns a warrant by ID +func (v Warrant) WarrantByIDHandler(w http.ResponseWriter, r *http.Request) { + civID := mux.Vars(r)["warrant_id"] + + zap.S().Debugf("warrant_id: %v", civID) + + cID, err := primitive.ObjectIDFromHex(civID) + if err != nil { + config.ErrorStatus("failed to get objectID from Hex", http.StatusBadRequest, w, err) + return + } + + dbResp, err := v.DB.FindOne(context.Background(), bson.M{"_id": cID}) + if err != nil { + config.ErrorStatus("failed to get warrant by ID", http.StatusNotFound, w, err) + return + } + + b, err := json.Marshal(dbResp) + if err != nil { + config.ErrorStatus("failed to marshal response", http.StatusInternalServerError, w, err) + return + } + w.WriteHeader(http.StatusOK) + w.Write(b) +} + +// WarrantsByUserIDHandler returns all warrants that contain the given userID +func (v Warrant) WarrantsByUserIDHandler(w http.ResponseWriter, r *http.Request) { + userID := mux.Vars(r)["user_id"] + activeCommunityID := r.URL.Query().Get("active_community_id") + status := r.URL.Query().Get("status") + Limit, err := strconv.Atoi(r.URL.Query().Get("limit")) + if err != nil { + zap.S().Warnf(fmt.Sprintf("limit not set, using default of %v", Limit|10)) + } + limit64 := int64(Limit) + Page = getPage(Page, r) + skip64 := int64(Page * Limit) + + zap.S().Debugf("user_id: '%v'", userID) + zap.S().Debugf("active_community: '%v'", activeCommunityID) + + var dbResp []models.Warrant + + // If the user is in a community then we want to search for warrants that + // are in that same community. This way each user can have different warrants + // across different communities. + // + // Likewise, if the user is not in a community, then we will display only the warrants + // that are not in a community + statusBool := true + if status == "false" { + statusBool = false + } + + err = nil + dbResp, err = v.DB.Find(context.TODO(), bson.M{ + "warrant.accusedID": userID, + "warrant.status": statusBool, + }, &options.FindOptions{Limit: &limit64, Skip: &skip64}) + if err != nil { + config.ErrorStatus("failed to get warrants", http.StatusNotFound, w, err) + return + } + + // Because the frontend requires that the data elements inside models.Warrants exist, if + // len == 0 then we will just return an empty data object + if len(dbResp) == 0 { + dbResp = []models.Warrant{} + } + b, err := json.Marshal(dbResp) + if err != nil { + config.ErrorStatus("failed to marshal response", http.StatusInternalServerError, w, err) + return + } + w.WriteHeader(http.StatusOK) + w.Write(b) +} diff --git a/api/handlers/warrant_test.go b/api/handlers/warrant_test.go new file mode 100644 index 0000000..73d25ce --- /dev/null +++ b/api/handlers/warrant_test.go @@ -0,0 +1,784 @@ +package handlers_test + +import ( + "encoding/json" + "errors" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gorilla/mux" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + + "github.com/linesmerrill/police-cad-api/api/handlers" + "github.com/linesmerrill/police-cad-api/databases" + "github.com/linesmerrill/police-cad-api/databases/mocks" + "github.com/linesmerrill/police-cad-api/models" +) + +func TestWarrant_WarrantByIDHandler(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/warrant/1234", nil) + if err != nil { + t.Fatal(err) + } + + req = mux.SetURLVars(req, map[string]string{"warrant_id": "1234"}) + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mocked-error")) + conn.(*mocks.CollectionHelper).On("FindOne", mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "warrants").Return(conn) + + warrantDatabase := databases.NewWarrantDatabase(db) + u := handlers.Warrant{ + DB: warrantDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.WarrantByIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusBadRequest { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get objectID from Hex", Error: "the provided hex string is not a valid ObjectID"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: \ngot: %v \nwant: %v", rr.Body.String(), expected) + } +} + +func TestWarrant_WarrantByIDHandlerJsonMarshalError(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/warrant/5fc51f58c72ff10004dca382", nil) + if err != nil { + t.Fatal(err) + } + + req = mux.SetURLVars(req, map[string]string{"warrant_id": "5fc51f58c72ff10004dca382"}) + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + x := map[string]interface{}{ + "foo": make(chan int), + } + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(**models.Warrant) + (*arg).Details.CreatedAt = x + + }) + conn.(*mocks.CollectionHelper).On("FindOne", mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "warrants").Return(conn) + + warrantDatabase := databases.NewWarrantDatabase(db) + u := handlers.Warrant{ + DB: warrantDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.WarrantByIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusInternalServerError { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to marshal response", Error: "json: unsupported type: chan int"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: \ngot: %v \nwant: %v", rr.Body.String(), expected) + } +} + +func TestWarrant_WarrantByIDHandlerFailedToFindOne(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/warrant/5fc51f58c72ff10004dca999", nil) + if err != nil { + t.Fatal(err) + } + + req = mux.SetURLVars(req, map[string]string{"warrant_id": "5fc51f58c72ff10004dca999"}) + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) + conn.(*mocks.CollectionHelper).On("FindOne", mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "warrants").Return(conn) + + warrantDatabase := databases.NewWarrantDatabase(db) + u := handlers.Warrant{ + DB: warrantDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.WarrantByIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusNotFound { + t.Errorf("handler returned wrong status code:\ngot %v\nwant %v", status, http.StatusBadRequest) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get warrant by ID", Error: "mongo: no documents in result"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestWarrant_WarrantByIDHandlerSuccess(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/warrant/5fc51f58c72ff10004dca382", nil) + if err != nil { + t.Fatal(err) + } + + req = mux.SetURLVars(req, map[string]string{"warrant_id": "5fc51f58c72ff10004dca382"}) + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(**models.Warrant) + (*arg).ID = "5fc51f58c72ff10004dca382" + + }) + conn.(*mocks.CollectionHelper).On("FindOne", mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "warrants").Return(conn) + + warrantDatabase := databases.NewWarrantDatabase(db) + u := handlers.Warrant{ + DB: warrantDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.WarrantByIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + testWarrant := models.Warrant{} + _ = json.Unmarshal(rr.Body.Bytes(), &testWarrant) + + assert.Equal(t, "5fc51f58c72ff10004dca382", testWarrant.ID) +} + +func TestWarrant_WarrantHandlerJsonMarshalError(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/warrants", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + x := map[string]interface{}{ + "foo": make(chan int), + } + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Warrant) + *arg = []models.Warrant{{Details: models.WarrantDetails{CreatedAt: x}}} + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "warrants").Return(conn) + + warrantDatabase := databases.NewWarrantDatabase(db) + u := handlers.Warrant{ + DB: warrantDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.WarrantHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusInternalServerError { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to marshal response", Error: "json: unsupported type: chan int"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestWarrant_WarrantHandlerFailedToFindOne(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/warrants", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "warrants").Return(conn) + + warrantDatabase := databases.NewWarrantDatabase(db) + u := handlers.Warrant{ + DB: warrantDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.WarrantHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusNotFound { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusNotFound) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get warrants", Error: "mongo: no documents in result"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestWarrant_WarrantHandlerSuccess(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/warrants", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Warrant) + *arg = []models.Warrant{{ID: "5fc51f58c72ff10004dca382"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "warrants").Return(conn) + + warrantDatabase := databases.NewWarrantDatabase(db) + u := handlers.Warrant{ + DB: warrantDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.WarrantHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testWarrant []models.Warrant + _ = json.Unmarshal(rr.Body.Bytes(), &testWarrant) + + assert.Equal(t, "5fc51f58c72ff10004dca382", testWarrant[0].ID) +} + +func TestWarrant_WarrantHandlerEmptyResponse(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/warrant", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var cursorHelper databases.CursorHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + cursorHelper = &mocks.CursorHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + cursorHelper.(*mocks.CursorHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Warrant) + *arg = nil + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) + db.(*MockDatabaseHelper).On("Collection", "warrants").Return(conn) + + warrantDatabase := databases.NewWarrantDatabase(db) + u := handlers.Warrant{ + DB: warrantDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.WarrantHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) + } + + expected := "[]" + if rr.Body.String() != expected { + t.Errorf("handler returned unexpected body: \ngot: %v \nwant: %v", rr.Body.String(), expected) + } +} + +func TestWarrant_WarrantsByUserIDHandlerJsonMarshalError(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/warrants/user/1234", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + x := map[string]interface{}{ + "foo": make(chan int), + } + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Warrant) + *arg = []models.Warrant{{Details: models.WarrantDetails{CreatedAt: x}}} + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "warrants").Return(conn) + + warrantDatabase := databases.NewWarrantDatabase(db) + u := handlers.Warrant{ + DB: warrantDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.WarrantsByUserIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusInternalServerError { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to marshal response", Error: "json: unsupported type: chan int"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestWarrant_WarrantsByUserIDHandlerFailedToFindOne(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/warrants/user/1234", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "warrants").Return(conn) + + warrantDatabase := databases.NewWarrantDatabase(db) + u := handlers.Warrant{ + DB: warrantDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.WarrantsByUserIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusNotFound { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusNotFound) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get warrants", Error: "mongo: no documents in result"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestWarrant_WarrantsByUserIDHandlerActiveCommunityIDFailedToFindOne(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/warrants/user/1234?active_community_id=1234", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(errors.New("mongo: no documents in result")) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "warrants").Return(conn) + + warrantDatabase := databases.NewWarrantDatabase(db) + u := handlers.Warrant{ + DB: warrantDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.WarrantsByUserIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusNotFound { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusNotFound) + } + + expected := models.ErrorMessageResponse{Response: models.MessageError{Message: "failed to get warrants", Error: "mongo: no documents in result"}} + b, _ := json.Marshal(expected) + if rr.Body.String() != string(b) { + t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) + } +} + +func TestWarrant_WarrantsByUserIDHandlerSuccess(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/warrants/user/61be0ebf22cfea7e7550f00e", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Warrant) + *arg = []models.Warrant{{ID: "5fc51f36c72ff10004dca381"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "warrants").Return(conn) + + warrantDatabase := databases.NewWarrantDatabase(db) + u := handlers.Warrant{ + DB: warrantDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.WarrantsByUserIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testWarrant []models.Warrant + _ = json.Unmarshal(rr.Body.Bytes(), &testWarrant) + + assert.Equal(t, "5fc51f36c72ff10004dca381", testWarrant[0].ID) +} + +func TestWarrant_WarrantsByUserIDHandlerSuccessWithStatusFalse(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/warrants/user/61be0ebf22cfea7e7550f00e?active_community_id=61c74b7b88e1abdac307bb39&status=false", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Warrant) + *arg = []models.Warrant{{ID: "5fc51f36c72ff10004dca381"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "warrants").Return(conn) + + warrantDatabase := databases.NewWarrantDatabase(db) + u := handlers.Warrant{ + DB: warrantDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.WarrantsByUserIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testWarrant []models.Warrant + _ = json.Unmarshal(rr.Body.Bytes(), &testWarrant) + + assert.Equal(t, "5fc51f36c72ff10004dca381", testWarrant[0].ID) +} + +func TestWarrant_WarrantsByUserIDHandlerSuccessWithActiveCommunityID(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/warrants/user/61be0ebf22cfea7e7550f00e?active_community_id=61c74b7b88e1abdac307bb39", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Warrant) + *arg = []models.Warrant{{ID: "5fc51f36c72ff10004dca381"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "warrants").Return(conn) + + warrantDatabase := databases.NewWarrantDatabase(db) + u := handlers.Warrant{ + DB: warrantDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.WarrantsByUserIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testWarrant []models.Warrant + _ = json.Unmarshal(rr.Body.Bytes(), &testWarrant) + + assert.Equal(t, "5fc51f36c72ff10004dca381", testWarrant[0].ID) +} + +func TestWarrant_WarrantsByUserIDHandlerSuccessWithNullCommunityID(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/warrants/user/61be0ebf22cfea7e7550f00e?active_community_id=null", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var singleResultHelper databases.SingleResultHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + singleResultHelper = &mocks.SingleResultHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + singleResultHelper.(*mocks.SingleResultHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Warrant) + *arg = []models.Warrant{{ID: "5fc51f36c72ff10004dca381"}} + + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(singleResultHelper) + db.(*MockDatabaseHelper).On("Collection", "warrants").Return(conn) + + warrantDatabase := databases.NewWarrantDatabase(db) + u := handlers.Warrant{ + DB: warrantDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.WarrantsByUserIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest) + } + + var testWarrant []models.Warrant + _ = json.Unmarshal(rr.Body.Bytes(), &testWarrant) + + assert.Equal(t, "5fc51f36c72ff10004dca381", testWarrant[0].ID) +} + +func TestWarrant_WarrantsByUserIDHandlerEmptyResponse(t *testing.T) { + req, err := http.NewRequest("GET", "/api/v1/warrants/user/1234", nil) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Authorization", "Bearer abc123") + + var db databases.DatabaseHelper + var client databases.ClientHelper + var conn databases.CollectionHelper + var cursorHelper databases.CursorHelper + + db = &MockDatabaseHelper{} // can be used as db = &mocks.DatabaseHelper{} + client = &mocks.ClientHelper{} + conn = &mocks.CollectionHelper{} + cursorHelper = &mocks.CursorHelper{} + + client.(*mocks.ClientHelper).On("StartSession").Return(nil, errors.New("mocked-error")) + db.(*MockDatabaseHelper).On("Client").Return(client) + cursorHelper.(*mocks.CursorHelper).On("Decode", mock.Anything).Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Warrant) + *arg = nil + }) + conn.(*mocks.CollectionHelper).On("Find", mock.Anything, mock.Anything, mock.Anything).Return(cursorHelper) + db.(*MockDatabaseHelper).On("Collection", "warrants").Return(conn) + + warrantDatabase := databases.NewWarrantDatabase(db) + u := handlers.Warrant{ + DB: warrantDatabase, + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(u.WarrantsByUserIDHandler) + + handler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) + } + + expected := "[]" + if rr.Body.String() != expected { + t.Errorf("handler returned unexpected body: \ngot: %v \nwant: %v", rr.Body.String(), expected) + } +} diff --git a/config/config_test.go b/config/config_test.go index 7057e6a..bc6fa97 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -2,6 +2,7 @@ package config import ( "errors" + "fmt" "net/http" "net/http/httptest" "os" @@ -41,3 +42,9 @@ func TestSetLoggerSetsLocalLogger(t *testing.T) { assert.NoError(t, err) assert.True(t, l.Core().Enabled(0)) } + +func TestSetLoggerCannotFindEnv(t *testing.T) { + l, err := setLogger("asdf") + assert.Equal(t, err, fmt.Errorf("cannot find ENV var so defaulting to debug level logging")) + assert.True(t, l.Core().Enabled(0)) +} diff --git a/databases/call.go b/databases/call.go index fb895f0..e8b9e58 100644 --- a/databases/call.go +++ b/databases/call.go @@ -6,14 +6,15 @@ import ( "context" "github.com/linesmerrill/police-cad-api/models" + "go.mongodb.org/mongo-driver/mongo/options" ) const callName = "calls" // CallDatabase contains the methods to use with the call database type CallDatabase interface { - FindOne(ctx context.Context, filter interface{}) (*models.Call, error) - Find(ctx context.Context, filter interface{}) ([]models.Call, error) + FindOne(context.Context, interface{}, ...*options.FindOneOptions) (*models.Call, error) + Find(context.Context, interface{}, ...*options.FindOptions) ([]models.Call, error) } type callDatabase struct { @@ -27,18 +28,18 @@ func NewCallDatabase(db DatabaseHelper) CallDatabase { } } -func (c *callDatabase) FindOne(ctx context.Context, filter interface{}) (*models.Call, error) { +func (c *callDatabase) FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (*models.Call, error) { call := &models.Call{} - err := c.db.Collection(callName).FindOne(ctx, filter).Decode(&call) + err := c.db.Collection(callName).FindOne(ctx, filter, opts...).Decode(&call) if err != nil { return nil, err } return call, nil } -func (c *callDatabase) Find(ctx context.Context, filter interface{}) ([]models.Call, error) { +func (c *callDatabase) Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) ([]models.Call, error) { var calls []models.Call - err := c.db.Collection(callName).Find(ctx, filter).Decode(&calls) + err := c.db.Collection(callName).Find(ctx, filter, opts...).Decode(&calls) if err != nil { return nil, err } diff --git a/databases/civilian.go b/databases/civilian.go index b35dfe6..959c026 100644 --- a/databases/civilian.go +++ b/databases/civilian.go @@ -6,14 +6,15 @@ import ( "context" "github.com/linesmerrill/police-cad-api/models" + "go.mongodb.org/mongo-driver/mongo/options" ) const civilianName = "civilians" // CivilianDatabase contains the methods to use with the civilian database type CivilianDatabase interface { - FindOne(ctx context.Context, filter interface{}) (*models.Civilian, error) - Find(ctx context.Context, filter interface{}) ([]models.Civilian, error) + FindOne(context.Context, interface{}, ...*options.FindOneOptions) (*models.Civilian, error) + Find(context.Context, interface{}, ...*options.FindOptions) ([]models.Civilian, error) } type civilianDatabase struct { @@ -27,18 +28,18 @@ func NewCivilianDatabase(db DatabaseHelper) CivilianDatabase { } } -func (c *civilianDatabase) FindOne(ctx context.Context, filter interface{}) (*models.Civilian, error) { +func (c *civilianDatabase) FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (*models.Civilian, error) { civilian := &models.Civilian{} - err := c.db.Collection(civilianName).FindOne(ctx, filter).Decode(&civilian) + err := c.db.Collection(civilianName).FindOne(ctx, filter, opts...).Decode(&civilian) if err != nil { return nil, err } return civilian, nil } -func (c *civilianDatabase) Find(ctx context.Context, filter interface{}) ([]models.Civilian, error) { +func (c *civilianDatabase) Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) ([]models.Civilian, error) { var civilians []models.Civilian - err := c.db.Collection(civilianName).Find(ctx, filter).Decode(&civilians) + err := c.db.Collection(civilianName).Find(ctx, filter, opts...).Decode(&civilians) if err != nil { return nil, err } diff --git a/databases/database.go b/databases/database.go index 667d03f..14fbd9f 100644 --- a/databases/database.go +++ b/databases/database.go @@ -18,8 +18,8 @@ type DatabaseHelper interface { // CollectionHelper contains all the methods defined for collections in this project type CollectionHelper interface { - FindOne(context.Context, interface{}) SingleResultHelper - Find(context.Context, interface{}) CursorHelper + FindOne(context.Context, interface{}, ...*options.FindOneOptions) SingleResultHelper + Find(context.Context, interface{}, ...*options.FindOptions) CursorHelper } // SingleResultHelper contains a single method to decode the result @@ -99,13 +99,13 @@ func (md *mongoDatabase) Client() ClientHelper { return &mongoClient{cl: client} } -func (mc *mongoCollection) FindOne(ctx context.Context, filter interface{}) SingleResultHelper { - singleResult := mc.coll.FindOne(ctx, filter) +func (mc *mongoCollection) FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) SingleResultHelper { + singleResult := mc.coll.FindOne(ctx, filter, opts...) return &mongoSingleResult{sr: singleResult} } -func (mc *mongoCollection) Find(ctx context.Context, filter interface{}) CursorHelper { - cursor, err := mc.coll.Find(ctx, filter) +func (mc *mongoCollection) Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) CursorHelper { + cursor, err := mc.coll.Find(ctx, filter, opts...) if err != nil { println(err) } diff --git a/databases/ems.go b/databases/ems.go index 503427f..ea8bf1f 100644 --- a/databases/ems.go +++ b/databases/ems.go @@ -6,14 +6,15 @@ import ( "context" "github.com/linesmerrill/police-cad-api/models" + "go.mongodb.org/mongo-driver/mongo/options" ) const emsName = "ems" // EmsDatabase contains the methods to use with the ems database type EmsDatabase interface { - FindOne(ctx context.Context, filter interface{}) (*models.Ems, error) - Find(ctx context.Context, filter interface{}) ([]models.Ems, error) + FindOne(context.Context, interface{}, ...*options.FindOneOptions) (*models.Ems, error) + Find(context.Context, interface{}, ...*options.FindOptions) ([]models.Ems, error) } type emsDatabase struct { @@ -27,18 +28,18 @@ func NewEmsDatabase(db DatabaseHelper) EmsDatabase { } } -func (c *emsDatabase) FindOne(ctx context.Context, filter interface{}) (*models.Ems, error) { +func (c *emsDatabase) FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (*models.Ems, error) { ems := &models.Ems{} - err := c.db.Collection(emsName).FindOne(ctx, filter).Decode(&ems) + err := c.db.Collection(emsName).FindOne(ctx, filter, opts...).Decode(&ems) if err != nil { return nil, err } return ems, nil } -func (c *emsDatabase) Find(ctx context.Context, filter interface{}) ([]models.Ems, error) { +func (c *emsDatabase) Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) ([]models.Ems, error) { var ems []models.Ems - err := c.db.Collection(emsName).Find(ctx, filter).Decode(&ems) + err := c.db.Collection(emsName).Find(ctx, filter, opts...).Decode(&ems) if err != nil { return nil, err } diff --git a/databases/emsvehicle.go b/databases/emsvehicle.go index 6d796e3..e5777a3 100644 --- a/databases/emsvehicle.go +++ b/databases/emsvehicle.go @@ -6,14 +6,15 @@ import ( "context" "github.com/linesmerrill/police-cad-api/models" + "go.mongodb.org/mongo-driver/mongo/options" ) const emsVehicleName = "emsvehicles" // EmsVehicleDatabase contains the methods to use with the emsVehicle database type EmsVehicleDatabase interface { - FindOne(ctx context.Context, filter interface{}) (*models.EmsVehicle, error) - Find(ctx context.Context, filter interface{}) ([]models.EmsVehicle, error) + FindOne(context.Context, interface{}, ...*options.FindOneOptions) (*models.EmsVehicle, error) + Find(context.Context, interface{}, ...*options.FindOptions) ([]models.EmsVehicle, error) } type emsVehicleDatabase struct { @@ -27,18 +28,18 @@ func NewEmsVehicleDatabase(db DatabaseHelper) EmsVehicleDatabase { } } -func (c *emsVehicleDatabase) FindOne(ctx context.Context, filter interface{}) (*models.EmsVehicle, error) { +func (c *emsVehicleDatabase) FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (*models.EmsVehicle, error) { emsVehicle := &models.EmsVehicle{} - err := c.db.Collection(emsVehicleName).FindOne(ctx, filter).Decode(&emsVehicle) + err := c.db.Collection(emsVehicleName).FindOne(ctx, filter, opts...).Decode(&emsVehicle) if err != nil { return nil, err } return emsVehicle, nil } -func (c *emsVehicleDatabase) Find(ctx context.Context, filter interface{}) ([]models.EmsVehicle, error) { +func (c *emsVehicleDatabase) Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) ([]models.EmsVehicle, error) { var emsVehicles []models.EmsVehicle - err := c.db.Collection(emsVehicleName).Find(ctx, filter).Decode(&emsVehicles) + err := c.db.Collection(emsVehicleName).Find(ctx, filter, opts...).Decode(&emsVehicles) if err != nil { return nil, err } diff --git a/databases/firearm.go b/databases/firearm.go index 5a4a504..5edae55 100644 --- a/databases/firearm.go +++ b/databases/firearm.go @@ -6,14 +6,15 @@ import ( "context" "github.com/linesmerrill/police-cad-api/models" + "go.mongodb.org/mongo-driver/mongo/options" ) const firearmName = "firearms" // FirearmDatabase contains the methods to use with the firearm database type FirearmDatabase interface { - FindOne(ctx context.Context, filter interface{}) (*models.Firearm, error) - Find(ctx context.Context, filter interface{}) ([]models.Firearm, error) + FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (*models.Firearm, error) + Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) ([]models.Firearm, error) } type firearmDatabase struct { @@ -27,7 +28,7 @@ func NewFirearmDatabase(db DatabaseHelper) FirearmDatabase { } } -func (c *firearmDatabase) FindOne(ctx context.Context, filter interface{}) (*models.Firearm, error) { +func (c *firearmDatabase) FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (*models.Firearm, error) { firearm := &models.Firearm{} err := c.db.Collection(firearmName).FindOne(ctx, filter).Decode(&firearm) if err != nil { @@ -36,9 +37,9 @@ func (c *firearmDatabase) FindOne(ctx context.Context, filter interface{}) (*mod return firearm, nil } -func (c *firearmDatabase) Find(ctx context.Context, filter interface{}) ([]models.Firearm, error) { +func (c *firearmDatabase) Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) ([]models.Firearm, error) { var firearms []models.Firearm - err := c.db.Collection(firearmName).Find(ctx, filter).Decode(&firearms) + err := c.db.Collection(firearmName).Find(ctx, filter, opts...).Decode(&firearms) if err != nil { return nil, err } diff --git a/databases/license.go b/databases/license.go new file mode 100644 index 0000000..d479842 --- /dev/null +++ b/databases/license.go @@ -0,0 +1,47 @@ +package databases + +// go generate: mockery --name LicenseDatabase + +import ( + "context" + + "github.com/linesmerrill/police-cad-api/models" + "go.mongodb.org/mongo-driver/mongo/options" +) + +const licenseName = "licenses" + +// LicenseDatabase contains the methods to use with the license database +type LicenseDatabase interface { + FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (*models.License, error) + Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) ([]models.License, error) +} + +type licenseDatabase struct { + db DatabaseHelper +} + +// NewLicenseDatabase initializes a new instance of license database with the provided db connection +func NewLicenseDatabase(db DatabaseHelper) LicenseDatabase { + return &licenseDatabase{ + db: db, + } +} + +func (c *licenseDatabase) FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (*models.License, error) { + license := &models.License{} + err := c.db.Collection(licenseName).FindOne(ctx, filter).Decode(&license) + if err != nil { + return nil, err + } + return license, nil +} + +func (c *licenseDatabase) Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) ([]models.License, error) { + var licenses []models.License + err := c.db.Collection(licenseName).Find(ctx, filter, opts...).Decode(&licenses) + if err != nil { + return nil, err + } + return licenses, nil +} diff --git a/databases/license_test.go b/databases/license_test.go new file mode 100644 index 0000000..877d994 --- /dev/null +++ b/databases/license_test.go @@ -0,0 +1,140 @@ +package databases_test + +import ( + "context" + "errors" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "go.mongodb.org/mongo-driver/bson" + + "github.com/linesmerrill/police-cad-api/config" + "github.com/linesmerrill/police-cad-api/databases" + "github.com/linesmerrill/police-cad-api/databases/mocks" + "github.com/linesmerrill/police-cad-api/models" +) + +func TestNewLicenseDatabase(t *testing.T) { + _ = os.Setenv("DB_URI", "mongodb://127.0.0.1:27017") + _ = os.Setenv("DB_NAME", "test") + conf := config.New() + + dbClient, err := databases.NewClient(conf) + assert.NoError(t, err) + + db := databases.NewDatabase(conf, dbClient) + + userDB := databases.NewLicenseDatabase(db) + + assert.NotEmpty(t, userDB) +} + +func TestLicenseDatabase_FindOne(t *testing.T) { + + // define variables for interfaces + var dbHelper databases.DatabaseHelper + var collectionHelper databases.CollectionHelper + var srHelperErr databases.SingleResultHelper + var srHelperCorrect databases.SingleResultHelper + + // set interfaces implementation to mocked structures + dbHelper = &mocks.DatabaseHelper{} + collectionHelper = &mocks.CollectionHelper{} + srHelperErr = &mocks.SingleResultHelper{} + srHelperCorrect = &mocks.SingleResultHelper{} + + srHelperErr.(*mocks.SingleResultHelper). + On("Decode", mock.Anything). + Return(errors.New("mocked-error")) + + srHelperCorrect.(*mocks.SingleResultHelper). + On("Decode", mock.Anything). + Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(**models.License) + (*arg).ID = "mocked-user" + }) + + collectionHelper.(*mocks.CollectionHelper). + On("FindOne", context.Background(), bson.M{"error": true}). + Return(srHelperErr) + + collectionHelper.(*mocks.CollectionHelper). + On("FindOne", context.Background(), bson.M{"error": false}). + Return(srHelperCorrect) + + dbHelper.(*mocks.DatabaseHelper). + On("Collection", "licenses").Return(collectionHelper) + + // Create new database with mocked Database interface + userDba := databases.NewLicenseDatabase(dbHelper) + + // Call method with defined filter, that in our mocked function returns + // mocked-error + user, err := userDba.FindOne(context.Background(), bson.M{"error": true}) + + assert.Empty(t, user) + assert.EqualError(t, err, "mocked-error") + + // Now call the same function with different filter for correct + // result + user, err = userDba.FindOne(context.Background(), bson.M{"error": false}) + + assert.Equal(t, &models.License{ID: "mocked-user"}, user) + assert.NoError(t, err) +} + +func TestLicenseDatabase_Find(t *testing.T) { + + // define variables for interfaces + var dbHelper databases.DatabaseHelper + var collectionHelper databases.CollectionHelper + var srHelperErr databases.SingleResultHelper + var srHelperCorrect databases.SingleResultHelper + + // set interfaces implementation to mocked structures + dbHelper = &mocks.DatabaseHelper{} + collectionHelper = &mocks.CollectionHelper{} + srHelperErr = &mocks.SingleResultHelper{} + srHelperCorrect = &mocks.SingleResultHelper{} + + srHelperErr.(*mocks.SingleResultHelper). + On("Decode", mock.Anything). + Return(errors.New("mocked-error")) + + srHelperCorrect.(*mocks.SingleResultHelper). + On("Decode", mock.Anything). + Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.License) + *arg = []models.License{{ID: "mocked-user"}} + }) + + collectionHelper.(*mocks.CollectionHelper). + On("Find", context.Background(), bson.M{"error": true}). + Return(srHelperErr) + + collectionHelper.(*mocks.CollectionHelper). + On("Find", context.Background(), bson.M{"error": false}). + Return(srHelperCorrect) + + dbHelper.(*mocks.DatabaseHelper). + On("Collection", "licenses").Return(collectionHelper) + + // Create new database with mocked Database interface + userDba := databases.NewLicenseDatabase(dbHelper) + + // Call method with defined filter, that in our mocked function returns + // mocked-error + user, err := userDba.Find(context.Background(), bson.M{"error": true}) + + assert.Empty(t, user) + assert.EqualError(t, err, "mocked-error") + + // Now call the same function with different filter for correct + // result + user, err = userDba.Find(context.Background(), bson.M{"error": false}) + + assert.Equal(t, []models.License{{ID: "mocked-user"}}, user) + assert.NoError(t, err) +} diff --git a/databases/mocks/CallDatabase.go b/databases/mocks/CallDatabase.go index ee26e1a..14b1bcc 100644 --- a/databases/mocks/CallDatabase.go +++ b/databases/mocks/CallDatabase.go @@ -8,6 +8,8 @@ import ( mock "github.com/stretchr/testify/mock" models "github.com/linesmerrill/police-cad-api/models" + + options "go.mongodb.org/mongo-driver/mongo/options" ) // CallDatabase is an autogenerated mock type for the CallDatabase type @@ -15,13 +17,20 @@ type CallDatabase struct { mock.Mock } -// Find provides a mock function with given fields: ctx, filter -func (_m *CallDatabase) Find(ctx context.Context, filter interface{}) ([]models.Call, error) { - ret := _m.Called(ctx, filter) +// Find provides a mock function with given fields: _a0, _a1, _a2 +func (_m *CallDatabase) Find(_a0 context.Context, _a1 interface{}, _a2 ...*options.FindOptions) ([]models.Call, error) { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) var r0 []models.Call - if rf, ok := ret.Get(0).(func(context.Context, interface{}) []models.Call); ok { - r0 = rf(ctx, filter) + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOptions) []models.Call); ok { + r0 = rf(_a0, _a1, _a2...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]models.Call) @@ -29,8 +38,8 @@ func (_m *CallDatabase) Find(ctx context.Context, filter interface{}) ([]models. } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, interface{}) error); ok { - r1 = rf(ctx, filter) + if rf, ok := ret.Get(1).(func(context.Context, interface{}, ...*options.FindOptions) error); ok { + r1 = rf(_a0, _a1, _a2...) } else { r1 = ret.Error(1) } @@ -38,13 +47,20 @@ func (_m *CallDatabase) Find(ctx context.Context, filter interface{}) ([]models. return r0, r1 } -// FindOne provides a mock function with given fields: ctx, filter -func (_m *CallDatabase) FindOne(ctx context.Context, filter interface{}) (*models.Call, error) { - ret := _m.Called(ctx, filter) +// FindOne provides a mock function with given fields: _a0, _a1, _a2 +func (_m *CallDatabase) FindOne(_a0 context.Context, _a1 interface{}, _a2 ...*options.FindOneOptions) (*models.Call, error) { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) var r0 *models.Call - if rf, ok := ret.Get(0).(func(context.Context, interface{}) *models.Call); ok { - r0 = rf(ctx, filter) + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOneOptions) *models.Call); ok { + r0 = rf(_a0, _a1, _a2...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*models.Call) @@ -52,8 +68,8 @@ func (_m *CallDatabase) FindOne(ctx context.Context, filter interface{}) (*model } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, interface{}) error); ok { - r1 = rf(ctx, filter) + if rf, ok := ret.Get(1).(func(context.Context, interface{}, ...*options.FindOneOptions) error); ok { + r1 = rf(_a0, _a1, _a2...) } else { r1 = ret.Error(1) } diff --git a/databases/mocks/CivilianDatabase.go b/databases/mocks/CivilianDatabase.go index aebd44f..20e67fb 100644 --- a/databases/mocks/CivilianDatabase.go +++ b/databases/mocks/CivilianDatabase.go @@ -8,6 +8,8 @@ import ( mock "github.com/stretchr/testify/mock" models "github.com/linesmerrill/police-cad-api/models" + + options "go.mongodb.org/mongo-driver/mongo/options" ) // CivilianDatabase is an autogenerated mock type for the CivilianDatabase type @@ -15,13 +17,20 @@ type CivilianDatabase struct { mock.Mock } -// Find provides a mock function with given fields: ctx, filter -func (_m *CivilianDatabase) Find(ctx context.Context, filter interface{}) ([]models.Civilian, error) { - ret := _m.Called(ctx, filter) +// Find provides a mock function with given fields: _a0, _a1, _a2 +func (_m *CivilianDatabase) Find(_a0 context.Context, _a1 interface{}, _a2 ...*options.FindOptions) ([]models.Civilian, error) { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) var r0 []models.Civilian - if rf, ok := ret.Get(0).(func(context.Context, interface{}) []models.Civilian); ok { - r0 = rf(ctx, filter) + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOptions) []models.Civilian); ok { + r0 = rf(_a0, _a1, _a2...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]models.Civilian) @@ -29,8 +38,8 @@ func (_m *CivilianDatabase) Find(ctx context.Context, filter interface{}) ([]mod } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, interface{}) error); ok { - r1 = rf(ctx, filter) + if rf, ok := ret.Get(1).(func(context.Context, interface{}, ...*options.FindOptions) error); ok { + r1 = rf(_a0, _a1, _a2...) } else { r1 = ret.Error(1) } @@ -38,13 +47,20 @@ func (_m *CivilianDatabase) Find(ctx context.Context, filter interface{}) ([]mod return r0, r1 } -// FindOne provides a mock function with given fields: ctx, filter -func (_m *CivilianDatabase) FindOne(ctx context.Context, filter interface{}) (*models.Civilian, error) { - ret := _m.Called(ctx, filter) +// FindOne provides a mock function with given fields: _a0, _a1, _a2 +func (_m *CivilianDatabase) FindOne(_a0 context.Context, _a1 interface{}, _a2 ...*options.FindOneOptions) (*models.Civilian, error) { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) var r0 *models.Civilian - if rf, ok := ret.Get(0).(func(context.Context, interface{}) *models.Civilian); ok { - r0 = rf(ctx, filter) + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOneOptions) *models.Civilian); ok { + r0 = rf(_a0, _a1, _a2...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*models.Civilian) @@ -52,8 +68,8 @@ func (_m *CivilianDatabase) FindOne(ctx context.Context, filter interface{}) (*m } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, interface{}) error); ok { - r1 = rf(ctx, filter) + if rf, ok := ret.Get(1).(func(context.Context, interface{}, ...*options.FindOneOptions) error); ok { + r1 = rf(_a0, _a1, _a2...) } else { r1 = ret.Error(1) } diff --git a/databases/mocks/CollectionHelper.go b/databases/mocks/CollectionHelper.go index 1c1d39e..1685ab6 100644 --- a/databases/mocks/CollectionHelper.go +++ b/databases/mocks/CollectionHelper.go @@ -7,6 +7,8 @@ import ( databases "github.com/linesmerrill/police-cad-api/databases" mock "github.com/stretchr/testify/mock" + + options "go.mongodb.org/mongo-driver/mongo/options" ) // CollectionHelper is an autogenerated mock type for the CollectionHelper type @@ -14,13 +16,20 @@ type CollectionHelper struct { mock.Mock } -// Find provides a mock function with given fields: _a0, _a1 -func (_m *CollectionHelper) Find(_a0 context.Context, _a1 interface{}) databases.CursorHelper { - ret := _m.Called(_a0, _a1) +// Find provides a mock function with given fields: _a0, _a1, _a2 +func (_m *CollectionHelper) Find(_a0 context.Context, _a1 interface{}, _a2 ...*options.FindOptions) databases.CursorHelper { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) var r0 databases.CursorHelper - if rf, ok := ret.Get(0).(func(context.Context, interface{}) databases.CursorHelper); ok { - r0 = rf(_a0, _a1) + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOptions) databases.CursorHelper); ok { + r0 = rf(_a0, _a1, _a2...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(databases.CursorHelper) @@ -30,13 +39,20 @@ func (_m *CollectionHelper) Find(_a0 context.Context, _a1 interface{}) databases return r0 } -// FindOne provides a mock function with given fields: _a0, _a1 -func (_m *CollectionHelper) FindOne(_a0 context.Context, _a1 interface{}) databases.SingleResultHelper { - ret := _m.Called(_a0, _a1) +// FindOne provides a mock function with given fields: _a0, _a1, _a2 +func (_m *CollectionHelper) FindOne(_a0 context.Context, _a1 interface{}, _a2 ...*options.FindOneOptions) databases.SingleResultHelper { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) var r0 databases.SingleResultHelper - if rf, ok := ret.Get(0).(func(context.Context, interface{}) databases.SingleResultHelper); ok { - r0 = rf(_a0, _a1) + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOneOptions) databases.SingleResultHelper); ok { + r0 = rf(_a0, _a1, _a2...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(databases.SingleResultHelper) diff --git a/databases/mocks/EmsDatabase.go b/databases/mocks/EmsDatabase.go index 221b045..dbad106 100644 --- a/databases/mocks/EmsDatabase.go +++ b/databases/mocks/EmsDatabase.go @@ -8,6 +8,8 @@ import ( mock "github.com/stretchr/testify/mock" models "github.com/linesmerrill/police-cad-api/models" + + options "go.mongodb.org/mongo-driver/mongo/options" ) // EmsDatabase is an autogenerated mock type for the EmsDatabase type @@ -15,13 +17,20 @@ type EmsDatabase struct { mock.Mock } -// Find provides a mock function with given fields: ctx, filter -func (_m *EmsDatabase) Find(ctx context.Context, filter interface{}) ([]models.Ems, error) { - ret := _m.Called(ctx, filter) +// Find provides a mock function with given fields: _a0, _a1, _a2 +func (_m *EmsDatabase) Find(_a0 context.Context, _a1 interface{}, _a2 ...*options.FindOptions) ([]models.Ems, error) { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) var r0 []models.Ems - if rf, ok := ret.Get(0).(func(context.Context, interface{}) []models.Ems); ok { - r0 = rf(ctx, filter) + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOptions) []models.Ems); ok { + r0 = rf(_a0, _a1, _a2...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]models.Ems) @@ -29,8 +38,8 @@ func (_m *EmsDatabase) Find(ctx context.Context, filter interface{}) ([]models.E } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, interface{}) error); ok { - r1 = rf(ctx, filter) + if rf, ok := ret.Get(1).(func(context.Context, interface{}, ...*options.FindOptions) error); ok { + r1 = rf(_a0, _a1, _a2...) } else { r1 = ret.Error(1) } @@ -38,13 +47,20 @@ func (_m *EmsDatabase) Find(ctx context.Context, filter interface{}) ([]models.E return r0, r1 } -// FindOne provides a mock function with given fields: ctx, filter -func (_m *EmsDatabase) FindOne(ctx context.Context, filter interface{}) (*models.Ems, error) { - ret := _m.Called(ctx, filter) +// FindOne provides a mock function with given fields: _a0, _a1, _a2 +func (_m *EmsDatabase) FindOne(_a0 context.Context, _a1 interface{}, _a2 ...*options.FindOneOptions) (*models.Ems, error) { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) var r0 *models.Ems - if rf, ok := ret.Get(0).(func(context.Context, interface{}) *models.Ems); ok { - r0 = rf(ctx, filter) + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOneOptions) *models.Ems); ok { + r0 = rf(_a0, _a1, _a2...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*models.Ems) @@ -52,8 +68,8 @@ func (_m *EmsDatabase) FindOne(ctx context.Context, filter interface{}) (*models } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, interface{}) error); ok { - r1 = rf(ctx, filter) + if rf, ok := ret.Get(1).(func(context.Context, interface{}, ...*options.FindOneOptions) error); ok { + r1 = rf(_a0, _a1, _a2...) } else { r1 = ret.Error(1) } diff --git a/databases/mocks/EmsVehicleDatabase.go b/databases/mocks/EmsVehicleDatabase.go index 2ea79db..1af2c8e 100644 --- a/databases/mocks/EmsVehicleDatabase.go +++ b/databases/mocks/EmsVehicleDatabase.go @@ -8,6 +8,8 @@ import ( mock "github.com/stretchr/testify/mock" models "github.com/linesmerrill/police-cad-api/models" + + options "go.mongodb.org/mongo-driver/mongo/options" ) // EmsVehicleDatabase is an autogenerated mock type for the EmsVehicleDatabase type @@ -15,13 +17,20 @@ type EmsVehicleDatabase struct { mock.Mock } -// Find provides a mock function with given fields: ctx, filter -func (_m *EmsVehicleDatabase) Find(ctx context.Context, filter interface{}) ([]models.EmsVehicle, error) { - ret := _m.Called(ctx, filter) +// Find provides a mock function with given fields: _a0, _a1, _a2 +func (_m *EmsVehicleDatabase) Find(_a0 context.Context, _a1 interface{}, _a2 ...*options.FindOptions) ([]models.EmsVehicle, error) { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) var r0 []models.EmsVehicle - if rf, ok := ret.Get(0).(func(context.Context, interface{}) []models.EmsVehicle); ok { - r0 = rf(ctx, filter) + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOptions) []models.EmsVehicle); ok { + r0 = rf(_a0, _a1, _a2...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]models.EmsVehicle) @@ -29,8 +38,8 @@ func (_m *EmsVehicleDatabase) Find(ctx context.Context, filter interface{}) ([]m } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, interface{}) error); ok { - r1 = rf(ctx, filter) + if rf, ok := ret.Get(1).(func(context.Context, interface{}, ...*options.FindOptions) error); ok { + r1 = rf(_a0, _a1, _a2...) } else { r1 = ret.Error(1) } @@ -38,13 +47,20 @@ func (_m *EmsVehicleDatabase) Find(ctx context.Context, filter interface{}) ([]m return r0, r1 } -// FindOne provides a mock function with given fields: ctx, filter -func (_m *EmsVehicleDatabase) FindOne(ctx context.Context, filter interface{}) (*models.EmsVehicle, error) { - ret := _m.Called(ctx, filter) +// FindOne provides a mock function with given fields: _a0, _a1, _a2 +func (_m *EmsVehicleDatabase) FindOne(_a0 context.Context, _a1 interface{}, _a2 ...*options.FindOneOptions) (*models.EmsVehicle, error) { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) var r0 *models.EmsVehicle - if rf, ok := ret.Get(0).(func(context.Context, interface{}) *models.EmsVehicle); ok { - r0 = rf(ctx, filter) + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOneOptions) *models.EmsVehicle); ok { + r0 = rf(_a0, _a1, _a2...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*models.EmsVehicle) @@ -52,8 +68,8 @@ func (_m *EmsVehicleDatabase) FindOne(ctx context.Context, filter interface{}) ( } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, interface{}) error); ok { - r1 = rf(ctx, filter) + if rf, ok := ret.Get(1).(func(context.Context, interface{}, ...*options.FindOneOptions) error); ok { + r1 = rf(_a0, _a1, _a2...) } else { r1 = ret.Error(1) } diff --git a/databases/mocks/FirearmDatabase.go b/databases/mocks/FirearmDatabase.go index 86231aa..9c0536e 100644 --- a/databases/mocks/FirearmDatabase.go +++ b/databases/mocks/FirearmDatabase.go @@ -8,6 +8,8 @@ import ( mock "github.com/stretchr/testify/mock" models "github.com/linesmerrill/police-cad-api/models" + + options "go.mongodb.org/mongo-driver/mongo/options" ) // FirearmDatabase is an autogenerated mock type for the FirearmDatabase type @@ -15,13 +17,20 @@ type FirearmDatabase struct { mock.Mock } -// Find provides a mock function with given fields: ctx, filter -func (_m *FirearmDatabase) Find(ctx context.Context, filter interface{}) ([]models.Firearm, error) { - ret := _m.Called(ctx, filter) +// Find provides a mock function with given fields: ctx, filter, opts +func (_m *FirearmDatabase) Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) ([]models.Firearm, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, filter) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) var r0 []models.Firearm - if rf, ok := ret.Get(0).(func(context.Context, interface{}) []models.Firearm); ok { - r0 = rf(ctx, filter) + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOptions) []models.Firearm); ok { + r0 = rf(ctx, filter, opts...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]models.Firearm) @@ -29,8 +38,8 @@ func (_m *FirearmDatabase) Find(ctx context.Context, filter interface{}) ([]mode } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, interface{}) error); ok { - r1 = rf(ctx, filter) + if rf, ok := ret.Get(1).(func(context.Context, interface{}, ...*options.FindOptions) error); ok { + r1 = rf(ctx, filter, opts...) } else { r1 = ret.Error(1) } @@ -38,13 +47,20 @@ func (_m *FirearmDatabase) Find(ctx context.Context, filter interface{}) ([]mode return r0, r1 } -// FindOne provides a mock function with given fields: ctx, filter -func (_m *FirearmDatabase) FindOne(ctx context.Context, filter interface{}) (*models.Firearm, error) { - ret := _m.Called(ctx, filter) +// FindOne provides a mock function with given fields: ctx, filter, opts +func (_m *FirearmDatabase) FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (*models.Firearm, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, filter) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) var r0 *models.Firearm - if rf, ok := ret.Get(0).(func(context.Context, interface{}) *models.Firearm); ok { - r0 = rf(ctx, filter) + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOneOptions) *models.Firearm); ok { + r0 = rf(ctx, filter, opts...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*models.Firearm) @@ -52,8 +68,8 @@ func (_m *FirearmDatabase) FindOne(ctx context.Context, filter interface{}) (*mo } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, interface{}) error); ok { - r1 = rf(ctx, filter) + if rf, ok := ret.Get(1).(func(context.Context, interface{}, ...*options.FindOneOptions) error); ok { + r1 = rf(ctx, filter, opts...) } else { r1 = ret.Error(1) } diff --git a/databases/mocks/LicenseDatabase.go b/databases/mocks/LicenseDatabase.go new file mode 100644 index 0000000..a55ac9a --- /dev/null +++ b/databases/mocks/LicenseDatabase.go @@ -0,0 +1,78 @@ +// Code generated by mockery v2.10.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + models "github.com/linesmerrill/police-cad-api/models" + + options "go.mongodb.org/mongo-driver/mongo/options" +) + +// LicenseDatabase is an autogenerated mock type for the LicenseDatabase type +type LicenseDatabase struct { + mock.Mock +} + +// Find provides a mock function with given fields: ctx, filter, opts +func (_m *LicenseDatabase) Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) ([]models.License, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, filter) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 []models.License + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOptions) []models.License); ok { + r0 = rf(ctx, filter, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]models.License) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, interface{}, ...*options.FindOptions) error); ok { + r1 = rf(ctx, filter, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindOne provides a mock function with given fields: ctx, filter, opts +func (_m *LicenseDatabase) FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (*models.License, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, filter) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *models.License + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOneOptions) *models.License); ok { + r0 = rf(ctx, filter, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.License) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, interface{}, ...*options.FindOneOptions) error); ok { + r1 = rf(ctx, filter, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/databases/mocks/VehicleDatabase.go b/databases/mocks/VehicleDatabase.go index 7514f8f..2a30372 100644 --- a/databases/mocks/VehicleDatabase.go +++ b/databases/mocks/VehicleDatabase.go @@ -8,6 +8,8 @@ import ( mock "github.com/stretchr/testify/mock" models "github.com/linesmerrill/police-cad-api/models" + + options "go.mongodb.org/mongo-driver/mongo/options" ) // VehicleDatabase is an autogenerated mock type for the VehicleDatabase type @@ -15,13 +17,20 @@ type VehicleDatabase struct { mock.Mock } -// Find provides a mock function with given fields: ctx, filter -func (_m *VehicleDatabase) Find(ctx context.Context, filter interface{}) ([]models.Vehicle, error) { - ret := _m.Called(ctx, filter) +// Find provides a mock function with given fields: _a0, _a1, _a2 +func (_m *VehicleDatabase) Find(_a0 context.Context, _a1 interface{}, _a2 ...*options.FindOptions) ([]models.Vehicle, error) { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) var r0 []models.Vehicle - if rf, ok := ret.Get(0).(func(context.Context, interface{}) []models.Vehicle); ok { - r0 = rf(ctx, filter) + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOptions) []models.Vehicle); ok { + r0 = rf(_a0, _a1, _a2...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]models.Vehicle) @@ -29,8 +38,8 @@ func (_m *VehicleDatabase) Find(ctx context.Context, filter interface{}) ([]mode } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, interface{}) error); ok { - r1 = rf(ctx, filter) + if rf, ok := ret.Get(1).(func(context.Context, interface{}, ...*options.FindOptions) error); ok { + r1 = rf(_a0, _a1, _a2...) } else { r1 = ret.Error(1) } @@ -38,13 +47,20 @@ func (_m *VehicleDatabase) Find(ctx context.Context, filter interface{}) ([]mode return r0, r1 } -// FindOne provides a mock function with given fields: ctx, filter -func (_m *VehicleDatabase) FindOne(ctx context.Context, filter interface{}) (*models.Vehicle, error) { - ret := _m.Called(ctx, filter) +// FindOne provides a mock function with given fields: _a0, _a1, _a2 +func (_m *VehicleDatabase) FindOne(_a0 context.Context, _a1 interface{}, _a2 ...*options.FindOneOptions) (*models.Vehicle, error) { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) var r0 *models.Vehicle - if rf, ok := ret.Get(0).(func(context.Context, interface{}) *models.Vehicle); ok { - r0 = rf(ctx, filter) + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOneOptions) *models.Vehicle); ok { + r0 = rf(_a0, _a1, _a2...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*models.Vehicle) @@ -52,8 +68,8 @@ func (_m *VehicleDatabase) FindOne(ctx context.Context, filter interface{}) (*mo } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, interface{}) error); ok { - r1 = rf(ctx, filter) + if rf, ok := ret.Get(1).(func(context.Context, interface{}, ...*options.FindOneOptions) error); ok { + r1 = rf(_a0, _a1, _a2...) } else { r1 = ret.Error(1) } diff --git a/databases/mocks/WarrantDatabase.go b/databases/mocks/WarrantDatabase.go new file mode 100644 index 0000000..2cf092f --- /dev/null +++ b/databases/mocks/WarrantDatabase.go @@ -0,0 +1,78 @@ +// Code generated by mockery v2.10.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + models "github.com/linesmerrill/police-cad-api/models" + + options "go.mongodb.org/mongo-driver/mongo/options" +) + +// WarrantDatabase is an autogenerated mock type for the WarrantDatabase type +type WarrantDatabase struct { + mock.Mock +} + +// Find provides a mock function with given fields: ctx, filter, opts +func (_m *WarrantDatabase) Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) ([]models.Warrant, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, filter) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 []models.Warrant + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOptions) []models.Warrant); ok { + r0 = rf(ctx, filter, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]models.Warrant) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, interface{}, ...*options.FindOptions) error); ok { + r1 = rf(ctx, filter, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindOne provides a mock function with given fields: ctx, filter, opts +func (_m *WarrantDatabase) FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (*models.Warrant, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, filter) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *models.Warrant + if rf, ok := ret.Get(0).(func(context.Context, interface{}, ...*options.FindOneOptions) *models.Warrant); ok { + r0 = rf(ctx, filter, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.Warrant) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, interface{}, ...*options.FindOneOptions) error); ok { + r1 = rf(ctx, filter, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/databases/vehicle.go b/databases/vehicle.go index c84639c..0532dd9 100644 --- a/databases/vehicle.go +++ b/databases/vehicle.go @@ -6,14 +6,15 @@ import ( "context" "github.com/linesmerrill/police-cad-api/models" + "go.mongodb.org/mongo-driver/mongo/options" ) const vehicleName = "vehicles" // VehicleDatabase contains the methods to use with the vehicle database type VehicleDatabase interface { - FindOne(ctx context.Context, filter interface{}) (*models.Vehicle, error) - Find(ctx context.Context, filter interface{}) ([]models.Vehicle, error) + FindOne(context.Context, interface{}, ...*options.FindOneOptions) (*models.Vehicle, error) + Find(context.Context, interface{}, ...*options.FindOptions) ([]models.Vehicle, error) } type vehicleDatabase struct { @@ -27,18 +28,18 @@ func NewVehicleDatabase(db DatabaseHelper) VehicleDatabase { } } -func (c *vehicleDatabase) FindOne(ctx context.Context, filter interface{}) (*models.Vehicle, error) { +func (c *vehicleDatabase) FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (*models.Vehicle, error) { vehicle := &models.Vehicle{} - err := c.db.Collection(vehicleName).FindOne(ctx, filter).Decode(&vehicle) + err := c.db.Collection(vehicleName).FindOne(ctx, filter, opts...).Decode(&vehicle) if err != nil { return nil, err } return vehicle, nil } -func (c *vehicleDatabase) Find(ctx context.Context, filter interface{}) ([]models.Vehicle, error) { +func (c *vehicleDatabase) Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) ([]models.Vehicle, error) { var vehicles []models.Vehicle - err := c.db.Collection(vehicleName).Find(ctx, filter).Decode(&vehicles) + err := c.db.Collection(vehicleName).Find(ctx, filter, opts...).Decode(&vehicles) if err != nil { return nil, err } diff --git a/databases/warrant.go b/databases/warrant.go new file mode 100644 index 0000000..1415a15 --- /dev/null +++ b/databases/warrant.go @@ -0,0 +1,47 @@ +package databases + +// go generate: mockery --name WarrantDatabase + +import ( + "context" + + "github.com/linesmerrill/police-cad-api/models" + "go.mongodb.org/mongo-driver/mongo/options" +) + +const warrantName = "warrants" + +// WarrantDatabase contains the methods to use with the warrant database +type WarrantDatabase interface { + FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (*models.Warrant, error) + Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) ([]models.Warrant, error) +} + +type warrantDatabase struct { + db DatabaseHelper +} + +// NewWarrantDatabase initializes a new instance of warrant database with the provided db connection +func NewWarrantDatabase(db DatabaseHelper) WarrantDatabase { + return &warrantDatabase{ + db: db, + } +} + +func (c *warrantDatabase) FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) (*models.Warrant, error) { + warrant := &models.Warrant{} + err := c.db.Collection(warrantName).FindOne(ctx, filter).Decode(&warrant) + if err != nil { + return nil, err + } + return warrant, nil +} + +func (c *warrantDatabase) Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) ([]models.Warrant, error) { + var warrants []models.Warrant + err := c.db.Collection(warrantName).Find(ctx, filter, opts...).Decode(&warrants) + if err != nil { + return nil, err + } + return warrants, nil +} diff --git a/databases/warrant_test.go b/databases/warrant_test.go new file mode 100644 index 0000000..6adfb57 --- /dev/null +++ b/databases/warrant_test.go @@ -0,0 +1,140 @@ +package databases_test + +import ( + "context" + "errors" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "go.mongodb.org/mongo-driver/bson" + + "github.com/linesmerrill/police-cad-api/config" + "github.com/linesmerrill/police-cad-api/databases" + "github.com/linesmerrill/police-cad-api/databases/mocks" + "github.com/linesmerrill/police-cad-api/models" +) + +func TestNewWarrantDatabase(t *testing.T) { + _ = os.Setenv("DB_URI", "mongodb://127.0.0.1:27017") + _ = os.Setenv("DB_NAME", "test") + conf := config.New() + + dbClient, err := databases.NewClient(conf) + assert.NoError(t, err) + + db := databases.NewDatabase(conf, dbClient) + + userDB := databases.NewWarrantDatabase(db) + + assert.NotEmpty(t, userDB) +} + +func TestWarrantDatabase_FindOne(t *testing.T) { + + // define variables for interfaces + var dbHelper databases.DatabaseHelper + var collectionHelper databases.CollectionHelper + var srHelperErr databases.SingleResultHelper + var srHelperCorrect databases.SingleResultHelper + + // set interfaces implementation to mocked structures + dbHelper = &mocks.DatabaseHelper{} + collectionHelper = &mocks.CollectionHelper{} + srHelperErr = &mocks.SingleResultHelper{} + srHelperCorrect = &mocks.SingleResultHelper{} + + srHelperErr.(*mocks.SingleResultHelper). + On("Decode", mock.Anything). + Return(errors.New("mocked-error")) + + srHelperCorrect.(*mocks.SingleResultHelper). + On("Decode", mock.Anything). + Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(**models.Warrant) + (*arg).ID = "mocked-user" + }) + + collectionHelper.(*mocks.CollectionHelper). + On("FindOne", context.Background(), bson.M{"error": true}). + Return(srHelperErr) + + collectionHelper.(*mocks.CollectionHelper). + On("FindOne", context.Background(), bson.M{"error": false}). + Return(srHelperCorrect) + + dbHelper.(*mocks.DatabaseHelper). + On("Collection", "warrants").Return(collectionHelper) + + // Create new database with mocked Database interface + userDba := databases.NewWarrantDatabase(dbHelper) + + // Call method with defined filter, that in our mocked function returns + // mocked-error + user, err := userDba.FindOne(context.Background(), bson.M{"error": true}) + + assert.Empty(t, user) + assert.EqualError(t, err, "mocked-error") + + // Now call the same function with different filter for correct + // result + user, err = userDba.FindOne(context.Background(), bson.M{"error": false}) + + assert.Equal(t, &models.Warrant{ID: "mocked-user"}, user) + assert.NoError(t, err) +} + +func TestWarrantDatabase_Find(t *testing.T) { + + // define variables for interfaces + var dbHelper databases.DatabaseHelper + var collectionHelper databases.CollectionHelper + var srHelperErr databases.SingleResultHelper + var srHelperCorrect databases.SingleResultHelper + + // set interfaces implementation to mocked structures + dbHelper = &mocks.DatabaseHelper{} + collectionHelper = &mocks.CollectionHelper{} + srHelperErr = &mocks.SingleResultHelper{} + srHelperCorrect = &mocks.SingleResultHelper{} + + srHelperErr.(*mocks.SingleResultHelper). + On("Decode", mock.Anything). + Return(errors.New("mocked-error")) + + srHelperCorrect.(*mocks.SingleResultHelper). + On("Decode", mock.Anything). + Return(nil).Run(func(args mock.Arguments) { + arg := args.Get(0).(*[]models.Warrant) + *arg = []models.Warrant{{ID: "mocked-user"}} + }) + + collectionHelper.(*mocks.CollectionHelper). + On("Find", context.Background(), bson.M{"error": true}). + Return(srHelperErr) + + collectionHelper.(*mocks.CollectionHelper). + On("Find", context.Background(), bson.M{"error": false}). + Return(srHelperCorrect) + + dbHelper.(*mocks.DatabaseHelper). + On("Collection", "warrants").Return(collectionHelper) + + // Create new database with mocked Database interface + userDba := databases.NewWarrantDatabase(dbHelper) + + // Call method with defined filter, that in our mocked function returns + // mocked-error + user, err := userDba.Find(context.Background(), bson.M{"error": true}) + + assert.Empty(t, user) + assert.EqualError(t, err, "mocked-error") + + // Now call the same function with different filter for correct + // result + user, err = userDba.Find(context.Background(), bson.M{"error": false}) + + assert.Equal(t, []models.Warrant{{ID: "mocked-user"}}, user) + assert.NoError(t, err) +} diff --git a/docs/docs.go b/docs/docs.go index f6abdf7..e1deb2c 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -152,25 +152,25 @@ type civiliansByUserIDParamsWrapper struct { ActiveCommunityID string `json:"active_community_id"` } -// swagger:route GET /api/v1/name-search name-search nameSearchID -// Get a civilian by firstname, lastname, date-of-birth and communityID. +// swagger:route GET /api/v1/civilians/search civilian civiliansByNameSearch +// Search civilians by supplied params. // responses: -// 200: nameSearchResponse +// 200: civiliansResponse -// Shows a civilian by the given firstname, lastname, date-of-birth and communityID -// swagger:response nameSearchResponse -type nameSearchResponseWrapper struct { +// Shows all civilians by search params +// swagger:response civiliansResponse +type civiliansByNameSearchResponseWrapper struct { // in:body Body []models.Civilian } -// swagger:parameters nameSearchID -type nameSearchParamsWrapper struct { +// swagger:parameters civiliansByNameSearch +type civiliansByNameSearchParamsWrapper struct { // in:query - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - DateOfBirth string `json:"dob"` - CommunityID string `json:"community_id"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` + DateOfBirth string `json:"date_of_birth"` + ActiveCommunityID string `json:"active_community_id"` } // swagger:route GET /api/v1/vehicle/{vehicle_id} vehicle vehicleByID @@ -217,6 +217,37 @@ type vehiclesByUserIDParamsWrapper struct { ActiveCommunityID string `json:"active_community_id"` } +// swagger:route GET /api/v1/vehicles/registered-owner/{registered_owner_id} vehicle vehiclesByRegisteredOwnerID +// Get all vehicles by RegisteredOwnerID. +// responses: +// 200: vehiclesResponse + +// Shows all vehicles by RegisteredOwnerID +// swagger:response vehiclesResponse +type vehiclesByRegisteredOwnerIDResponseWrapper struct { + // in:body + Body []models.Vehicle +} + +// swagger:route GET /api/v1/vehicles/search vehicle vehiclesByPlateSearch +// Get all vehicles by plate. +// responses: +// 200: vehiclesResponse + +// Shows all vehicles by plate +// swagger:response vehiclesResponse +type vehiclesByPlateSearchResponseWrapper struct { + // in:body + Body []models.Vehicle +} + +// swagger:parameters vehiclesByPlateSearch +type vehiclesByPlateSearchParamsWrapper struct { + // in:query + Plate string `json:"plate"` + ActiveCommunityID string `json:"active_community_id"` +} + // swagger:route GET /api/v1/firearm/{firearm_id} firearm firearmByID // Get a firearm by ID. // responses: @@ -261,6 +292,74 @@ type firearmsByUserIDParamsWrapper struct { ActiveCommunityID string `json:"active_community_id"` } +// swagger:route GET /api/v1/firearms/registered-owner/{registered_owner_id} firearm firearmsByRegisteredOwnerID +// Get all firearms by RegisteredOwnerID. +// responses: +// 200: firearmsResponse + +// Shows all firearms by RegisteredOwnerID +// swagger:response firearmsResponse +type firearmsByRegisteredOwnerIDResponseWrapper struct { + // in:body + Body []models.Firearm +} + +// swagger:route GET /api/v1/license/{license_id} license licenseByID +// Get a license by ID. +// responses: +// 200: licenseByIDResponse +// 404: errorMessageResponse + +// Shows a license by the given license ID {license_id} +// swagger:response licenseByIDResponse +type licenseByIDResponseWrapper struct { + // in:body + Body models.License +} + +// swagger:route GET /api/v1/licenses license licenses +// Get all licenses. +// responses: +// 200: licensesResponse +// 404: errorMessageResponse + +// Shows all licenses. +// swagger:response licensesResponse +type licensesResponseWrapper struct { + // in:body + Body []models.License +} + +// swagger:route GET /api/v1/licenses/user/{user_id} license licensesByUserID +// Get all licenses by userID. +// responses: +// 200: licensesResponse + +// Shows all licenses by userID +// swagger:response licensesResponse +type licensesByUserIDResponseWrapper struct { + // in:body + Body []models.License +} + +// swagger:parameters licensesByUserID +type licensesByUserIDParamsWrapper struct { + // in:query + ActiveCommunityID string `json:"active_community_id"` +} + +// swagger:route GET /api/v1/licenses/owner/{owner_id} license licensesByOwnerID +// Get all licenses by OwnerID. +// responses: +// 200: licensesResponse + +// Shows all licenses by OwnerID +// swagger:response licensesResponse +type licensesByOwnerIDResponseWrapper struct { + // in:body + Body []models.License +} + // swagger:route GET /api/v1/ems/{ems_id} ems emsByID // Get a ems by ID. // responses: @@ -392,3 +491,47 @@ type callByCommunityIDParamsWrapper struct { // in:query Status bool `json:"status"` } + +// swagger:route GET /api/v1/warrant/{warrant_id} warrant warrantByID +// Get a warrant by ID. +// responses: +// 200: warrantByIDResponse +// 404: errorMessageResponse + +// Shows a warrant by the given warrant ID {warrant_id} +// swagger:response warrantByIDResponse +type warrantByIDResponseWrapper struct { + // in:body + Body models.Warrant +} + +// swagger:route GET /api/v1/warrants warrant warrants +// Get all warrants. +// responses: +// 200: warrantsResponse +// 404: errorMessageResponse + +// Shows all warrants. +// swagger:response warrantsResponse +type warrantsResponseWrapper struct { + // in:body + Body []models.Warrant +} + +// swagger:route GET /api/v1/warrants/user/{user_id} warrant warrantsByUserID +// Get all warrants by userID. +// responses: +// 200: warrantsResponse + +// Shows all warrants by userID +// swagger:response warrantsResponse +type warrantsByUserIDResponseWrapper struct { + // in:body + Body []models.Warrant +} + +// swagger:parameters warrantsByUserID +type warrantsByUserIDParamsWrapper struct { + // in:query + Page string `json:"page"` +} diff --git a/docs/swagger.yaml b/docs/swagger.yaml index b487860..0f76ab8 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -393,6 +393,57 @@ definitions: x-go-name: Alive type: object x-go-package: github.com/linesmerrill/police-cad-api/models + License: + description: License holds the structure for the license collection in mongo + properties: + __v: + format: int32 + type: integer + x-go-name: Version + _id: + type: string + x-go-name: ID + license: + $ref: '#/definitions/LicenseDetails' + type: object + x-go-package: github.com/linesmerrill/police-cad-api/models + LicenseDetails: + description: |- + LicenseDetails holds the structure for the inner user structure as + defined in the license collection in mongo + properties: + activeCommunityID: + type: string + x-go-name: ActiveCommunityID + additionalNotes: + type: string + x-go-name: AdditionalNotes + createdAt: + type: object + x-go-name: CreatedAt + expirationDate: + type: string + x-go-name: ExpirationDate + licenseType: + type: string + x-go-name: LicenseType + ownerID: + type: string + x-go-name: OwnerID + ownerName: + type: string + x-go-name: OwnerName + status: + type: string + x-go-name: Status + updatedAt: + type: object + x-go-name: UpdatedAt + userID: + type: string + x-go-name: UserID + type: object + x-go-package: github.com/linesmerrill/police-cad-api/models MessageError: description: MessageError contains the inner details for the error message response properties: @@ -524,6 +575,56 @@ definitions: x-go-name: Vin type: object x-go-package: github.com/linesmerrill/police-cad-api/models + Warrant: + description: Warrant holds the structure for the warrant collection in mongo + properties: + __v: + format: int32 + type: integer + x-go-name: Version + _id: + type: string + x-go-name: ID + warrant: + $ref: '#/definitions/WarrantDetails' + type: object + x-go-package: github.com/linesmerrill/police-cad-api/models + WarrantDetails: + description: |- + WarrantDetails holds the structure for the inner user structure as + defined in the warrant collection in mongo + properties: + accusedFirstName: + type: string + x-go-name: AccusedFirstName + accusedID: + type: string + x-go-name: AccusedID + accusedLastName: + type: string + x-go-name: AccusedLastName + clearingOfficerID: + type: string + x-go-name: ClearingOfficerID + createdAt: + type: object + x-go-name: CreatedAt + reasons: + items: + type: string + type: array + x-go-name: Reasons + reportingOfficerID: + type: string + x-go-name: ReportingOfficerID + status: + type: boolean + x-go-name: Status + updatedAt: + type: object + x-go-name: UpdatedAt + type: object + x-go-package: github.com/linesmerrill/police-cad-api/models host: https://police-cad-api.herokuapp.com info: description: Documentation of Lines Police CAD API. @@ -586,6 +687,32 @@ paths: summary: Get all civilians. tags: - civilian + /api/v1/civilians/search: + get: + operationId: civiliansByNameSearch + parameters: + - in: query + name: first_name + type: string + x-go-name: FirstName + - in: query + name: last_name + type: string + x-go-name: LastName + - in: query + name: date_of_birth + type: string + x-go-name: DateOfBirth + - in: query + name: active_community_id + type: string + x-go-name: ActiveCommunityID + responses: + "200": + $ref: '#/responses/civiliansResponse' + summary: Search civilians by supplied params. + tags: + - civilian /api/v1/civilians/user/{user_id}: get: operationId: civiliansByUserID @@ -727,6 +854,15 @@ paths: summary: Get all firearms. tags: - firearm + /api/v1/firearms/registered-owner/{registered_owner_id}: + get: + operationId: firearmsByRegisteredOwnerID + responses: + "200": + $ref: '#/responses/firearmsResponse' + summary: Get all firearms by RegisteredOwnerID. + tags: + - firearm /api/v1/firearms/user/{user_id}: get: operationId: firearmsByUserID @@ -741,32 +877,51 @@ paths: summary: Get all firearms by userID. tags: - firearm - /api/v1/name-search: + /api/v1/license/{license_id}: + get: + operationId: licenseByID + responses: + "200": + $ref: '#/responses/licenseByIDResponse' + "404": + $ref: '#/responses/errorMessageResponse' + summary: Get a license by ID. + tags: + - license + /api/v1/licenses: + get: + operationId: licenses + responses: + "200": + $ref: '#/responses/licensesResponse' + "404": + $ref: '#/responses/errorMessageResponse' + summary: Get all licenses. + tags: + - license + /api/v1/licenses/owner/{owner_id}: get: - operationId: nameSearchID + operationId: licensesByOwnerID + responses: + "200": + $ref: '#/responses/licensesResponse' + summary: Get all licenses by OwnerID. + tags: + - license + /api/v1/licenses/user/{user_id}: + get: + operationId: licensesByUserID parameters: - in: query - name: first_name - type: string - x-go-name: FirstName - - in: query - name: last_name - type: string - x-go-name: LastName - - in: query - name: dob - type: string - x-go-name: DateOfBirth - - in: query - name: community_id + name: active_community_id type: string - x-go-name: CommunityID + x-go-name: ActiveCommunityID responses: "200": - $ref: '#/responses/nameSearchResponse' - summary: Get a civilian by firstname, lastname, date-of-birth and communityID. + $ref: '#/responses/licensesResponse' + summary: Get all licenses by userID. tags: - - name-search + - license /api/v1/user/{user_id}: get: operationId: userByID @@ -807,6 +962,33 @@ paths: summary: Get all vehicles. tags: - vehicle + /api/v1/vehicles/registered-owner/{registered_owner_id}: + get: + operationId: vehiclesByRegisteredOwnerID + responses: + "200": + $ref: '#/responses/vehiclesResponse' + summary: Get all vehicles by RegisteredOwnerID. + tags: + - vehicle + /api/v1/vehicles/search: + get: + operationId: vehiclesByPlateSearch + parameters: + - in: query + name: plate + type: string + x-go-name: Plate + - in: query + name: active_community_id + type: string + x-go-name: ActiveCommunityID + responses: + "200": + $ref: '#/responses/vehiclesResponse' + summary: Get all vehicles by plate. + tags: + - vehicle /api/v1/vehicles/user/{user_id}: get: operationId: vehiclesByUserID @@ -821,6 +1003,42 @@ paths: summary: Get all vehicles by userID. tags: - vehicle + /api/v1/warrant/{warrant_id}: + get: + operationId: warrantByID + responses: + "200": + $ref: '#/responses/warrantByIDResponse' + "404": + $ref: '#/responses/errorMessageResponse' + summary: Get a warrant by ID. + tags: + - warrant + /api/v1/warrants: + get: + operationId: warrants + responses: + "200": + $ref: '#/responses/warrantsResponse' + "404": + $ref: '#/responses/errorMessageResponse' + summary: Get all warrants. + tags: + - warrant + /api/v1/warrants/user/{user_id}: + get: + operationId: warrantsByUserID + parameters: + - in: query + name: page + type: string + x-go-name: Page + responses: + "200": + $ref: '#/responses/warrantsResponse' + summary: Get all warrants by userID. + tags: + - warrant /health: get: operationId: healthEndpointID @@ -848,7 +1066,7 @@ responses: schema: $ref: '#/definitions/Civilian' civiliansResponse: - description: Shows all civilians by userID + description: Shows all civilians by search params schema: items: $ref: '#/definitions/Civilian' @@ -897,7 +1115,7 @@ responses: schema: $ref: '#/definitions/Firearm' firearmsResponse: - description: Shows all firearms by userID + description: Shows all firearms by RegisteredOwnerID schema: items: $ref: '#/definitions/Firearm' @@ -907,12 +1125,15 @@ responses: means it is not. schema: $ref: '#/definitions/HealthCheckResponse' - nameSearchResponse: - description: Shows a civilian by the given firstname, lastname, date-of-birth - and communityID + licenseByIDResponse: + description: Shows a license by the given license ID {license_id} + schema: + $ref: '#/definitions/License' + licensesResponse: + description: Shows all licenses by OwnerID schema: items: - $ref: '#/definitions/Civilian' + $ref: '#/definitions/License' type: array userByIDResponse: description: Shows the user by the given userID {user_id} @@ -929,11 +1150,21 @@ responses: schema: $ref: '#/definitions/Vehicle' vehiclesResponse: - description: Shows all vehicles by userID + description: Shows all vehicles by plate schema: items: $ref: '#/definitions/Vehicle' type: array + warrantByIDResponse: + description: Shows a warrant by the given warrant ID {warrant_id} + schema: + $ref: '#/definitions/Warrant' + warrantsResponse: + description: Shows all warrants by userID + schema: + items: + $ref: '#/definitions/Warrant' + type: array schemes: - https securityDefinitions: diff --git a/models/license.go b/models/license.go new file mode 100644 index 0000000..ade35ca --- /dev/null +++ b/models/license.go @@ -0,0 +1,23 @@ +package models + +// License holds the structure for the license collection in mongo +type License struct { + ID string `json:"_id" bson:"_id"` + Details LicenseDetails `json:"license" bson:"license"` + Version int32 `json:"__v" bson:"__v"` +} + +// LicenseDetails holds the structure for the inner user structure as +// defined in the license collection in mongo +type LicenseDetails struct { + LicenseType string `json:"licenseType" bson:"licenseType"` + Status string `json:"status" bson:"status"` + ExpirationDate string `json:"expirationDate" bson:"expirationDate"` + AdditionalNotes string `json:"additionalNotes" bson:"additionalNotes"` + OwnerID string `json:"ownerID" bson:"ownerID"` + OwnerName string `json:"ownerName" bson:"ownerName"` + ActiveCommunityID string `json:"activeCommunityID" bson:"activeCommunityID"` + UserID string `json:"userID" bson:"userID"` + CreatedAt interface{} `json:"createdAt" bson:"createdAt"` + UpdatedAt interface{} `json:"updatedAt" bson:"updatedAt"` +} diff --git a/models/warrant.go b/models/warrant.go new file mode 100644 index 0000000..c3c6688 --- /dev/null +++ b/models/warrant.go @@ -0,0 +1,22 @@ +package models + +// Warrant holds the structure for the warrant collection in mongo +type Warrant struct { + ID string `json:"_id" bson:"_id"` + Details WarrantDetails `json:"warrant" bson:"warrant"` + Version int32 `json:"__v" bson:"__v"` +} + +// WarrantDetails holds the structure for the inner user structure as +// defined in the warrant collection in mongo +type WarrantDetails struct { + Status bool `json:"status" bson:"status"` + AccusedID string `json:"accusedID" bson:"accusedID"` + AccusedFirstName string `json:"accusedFirstName" bson:"accusedFirstName"` + AccusedLastName string `json:"accusedLastName" bson:"accusedLastName"` + Reasons []string `json:"reasons" bson:"reasons"` + ReportingOfficerID string `json:"reportingOfficerID" bson:"reportingOfficerID"` + ClearingOfficerID string `json:"clearingOfficerID" bson:"clearingOfficerID"` + CreatedAt interface{} `json:"createdAt" bson:"createdAt"` + UpdatedAt interface{} `json:"updatedAt" bson:"updatedAt"` +}