diff --git a/documentation/docs/reference/services/Event.md b/documentation/docs/reference/services/Event.md index 99aac9bf..6ddfa529 100644 --- a/documentation/docs/reference/services/Event.md +++ b/documentation/docs/reference/services/Event.md @@ -23,7 +23,10 @@ Response format: } ], "sponsor": "Example sponsor", - "eventType": "WORKSHOP" + "eventType": "WORKSHOP", + "inPersonPoints": 10, + "inPersonVirtPoints": 5, + "virtualPoints": 3 } ``` @@ -51,7 +54,10 @@ Response format: } ], "sponsor": "Example sponsor", - "eventType": "WORKSHOP" + "eventType": "WORKSHOP", + "inPersonPoints": 10, + "inPersonVirtPoints": 5, + "virtualPoints": 3 }, { "id": "52fdfcab71282654f163f5f0f9a621d72", @@ -68,7 +74,10 @@ Response format: } ], "sponsor": "Example sponsor", - "eventType": "WORKSHOP" + "eventType": "WORKSHOP", + "inPersonPoints": 20, + "inPersonVirtPoints": 10, + "virtualPoints": 5 } ] } @@ -98,11 +107,14 @@ Response format: } ], "sponsor": "Example sponsor", - "eventType": "WORKSHOP" + "eventType": "WORKSHOP", + "inPersonPoints": 10, + "inPersonVirtPoints": 5, + "virtualPoints": 3 }, { "id": "9566c74d10037c4d7bbb0407d1e2c649", - "name": "Example Event 10", + "name": "Example Event 11", "description": "This is a description", "startTime": 1532202702, "endTime": 1532212702, @@ -115,7 +127,10 @@ Response format: } ], "sponsor": "Example sponsor", - "eventType": "WORKSHOP" + "eventType": "WORKSHOP", + "inPersonPoints": 20, + "inPersonVirtPoints": 10, + "virtualPoints": 5 } ] } @@ -144,7 +159,10 @@ Request format: "latitude": 40.1138, "longitude": -88.2249 } - ] + ], + "inPersonPoints": 10, + "inPersonVirtPoints": 5, + "virtualPoints": 3 } ``` @@ -165,7 +183,10 @@ Response format: } ], "sponsor": "Example sponsor", - "eventType": "WORKSHOP" + "eventType": "WORKSHOP", + "inPersonPoints": 10, + "inPersonVirtPoints": 5, + "virtualPoints": 3 } ``` @@ -191,7 +212,10 @@ Response format: } ], "sponsor": "Example sponsor", - "eventType": "WORKSHOP" + "eventType": "WORKSHOP", + "inPersonPoints": 10, + "inPersonVirtPoints": 7, + "virtualPoints": 3 } ``` @@ -217,7 +241,10 @@ Request format: "latitude": 40.1138, "longitude": -88.2249 } - ] + ], + "inPersonPoints": 20, + "inPersonVirtPoints": 10, + "virtualPoints": 5 } ``` @@ -238,7 +265,10 @@ Response format: } ], "sponsor": "Example sponsor", - "eventType": "WORKSHOP" + "eventType": "WORKSHOP", + "inPersonPoints": 20, + "inPersonVirtPoints": 10, + "virtualPoints": 5 } ``` @@ -367,29 +397,41 @@ Response format: GET /event/code/{id}/ ---------------------------- -Gets a struct that contains information about the event code (generated upon event creation) and expiration time. +Gets an array of structs that contains information about the event codes (generated upon event creation) and expiration times. By convention, event checkin codes will be 6 bytes long. Response format: ``` -{ - "id": "52fdfc072182654f163f5f0f9a621d72", - "code": "sample_code", - "expiration": 1521388800 -} - +[ + { + "codeID": "sample_code_1", + "eventID": "52fdfc072182654f163f5f0f9a621d72", + "isVirtual": false, + "expiration": 1521388800 + }, + { + "codeID": "sample_code_2", + "eventID": "52fdfc072182654f163f5f0f9a621d72", + "isVirtual": true, + "expiration": 1521388800 + } +] ``` -PUT /event/code/{id}/ +POST /event/code/ ---------------------------- -Updates a struct that contains information about the event code (generated upon event creation) and expiration time. +Upserts a struct that contains information about the event code (generated upon event creation) and expiration time. + +NOTE: Once created, the code ID cannot be changed. Request format: ``` { - "code": "new_code", - "expiration": 1521388800 + "codeID": "code", + "eventID": "52fdfc072182654f163f5f0f9a621d72", + "isVirtual": true, + "expiration": 1521388800 } ``` @@ -397,9 +439,10 @@ Request format: Response format: ``` { - "id": "52fdfc072182654f163f5f0f9a621d72", - "code": "new_code", - "expiration": 1521388800 + "codeID": "code", + "eventID": "52fdfc072182654f163f5f0f9a621d72", + "isVirtual": true, + "expiration": 1521388800 } ``` @@ -409,6 +452,8 @@ POST /event/checkin/ Retrieves a struct that contains information about the event checkin status, point increment value, and total point number. Takes in a struct that contains an event checkin code. +The endpoint will check the use HackIllinois-Identity field to determine if the user redeeming the points registered for virtual or in-person. It will compare this to the scanned code and will award points accordingly. (e.g. If registered for virtual, give `virtualPoints`. If registered for in-person but attended virtually, give `inPersonVirtPoints`. If registered for in-person and attended in-person, give `inPersonPoints`.) + Valid values for `status` are `Success`, `InvalidCode`, `InvalidTime`, `AlreadyCheckedIn`. When `status != Success`, the `newPoints` and `totalPoints` fields will equal `-1` and should be ignored. Request format: diff --git a/documentation/docs/reference/services/Profile.md b/documentation/docs/reference/services/Profile.md index 90d85b27..d91c4d08 100644 --- a/documentation/docs/reference/services/Profile.md +++ b/documentation/docs/reference/services/Profile.md @@ -6,8 +6,6 @@ GET /profile/ Returns the profile stored for the current user. -Valid values for ``teamStatus`` are ``LOOKING_FOR_MEMBERS``, ``LOOKING_FOR_TEAM``, and ``NOT_LOOKING``. - ***The `id` in the profile service refers to a separate, randomly-generated, profile-only id. This is different from the (user) `id` used in other services. When a profile is created, a mapping from the user `id` to the profile `id` is stored in the database.*** We will distinguish user id and profile id by using `github123456` and `profileid123456` for each, respectively, in the examples below. @@ -19,12 +17,7 @@ Response format: "firstName": "John", "lastName": "Doe", "points": 2021, - "timezone": "Americas UTC+8", - "avatarUrl": "https://github.com/.../profile.jpg", - "discord": "patrick#1234", - "teamStatus": "LOOKING_FOR_TEAM", - "description": "Lorem Ipsum…", - "interests": ["C++", "Machine Learning"] + "isVirtual": false } ``` @@ -32,7 +25,7 @@ Response format: GET /profile/{id}/ ------------------------- -Returns the profile stored for user that has the ID ``{id}``. +Returns the profile stored for user that has the profile ID ``{id}``. Response format: ``` @@ -41,16 +34,29 @@ Response format: "firstName": "John", "lastName": "Doe", "points": 2021, - "timezone": "Americas UTC+8", - "avatarUrl": "https://github.com/.../profile.jpg", - "discord": "patrick#1234", - "teamStatus": "LOOKING_FOR_TEAM", - "description": "Lorem Ipsum…", - "interests": ["C++", "Machine Learning"] + "isVirtual": false } ``` -GET /profile/list/?teamStatus=value&interests=value,value,value&limit=value +GET /profile/user/{id}/ +------------------------- + +**Internal use only.** + +Returns the profile stored for user that has the user ID ``{id}``. + +Response format: +``` +{ + "id": "profileid123456", + "firstName": "John", + "lastName": "Doe", + "points": 2021, + "isVirtual": false +} +``` + +GET /profile/list/?isVirtual=value&interests=value,value,value&limit=value ------------------------- **Internal use only.** @@ -61,8 +67,6 @@ teamStatus is a string matching the user's team status. interests is a comma-separated string representing the user's interests. -- i.e if the user's interests are ["C++", "Machine Learning"], you can filter on this by sending ``interests="C++,Machine Learning"`` - If a ``limit`` parameter is provided, it will return the first matching ``limit`` profiles. Otherwise, it will return all of the matched profiles. If no parameters are provided, it returns all profiles that are in the database. @@ -76,24 +80,14 @@ Response format: "firstName": "John", "lastName": "Doe", "points": 2021, - "timezone": "Americas UTC+8", - "avatarUrl": "https://github.com/.../profile.jpg", - "discord": "patrick#1234", - "teamStatus": "LOOKING_FOR_TEAM", - "description": "Lorem Ipsum…", - "interests": ["C++", "Machine Learning"] + "isVirtual": false }, { "id": "profileid123456", "firstName": "John", "lastName": "Doe", "points": 2021, - "timezone": "Americas UTC+8", - "avatarUrl": "https://github.com/.../profile.jpg", - "discord": "patrick#1234", - "teamStatus": "LOOKING_FOR_MEMBERS", - "description": "Lorem Ipsum…", - "interests": ["C++", "Machine Learning"] + "isVirtual": false }, ] } @@ -109,12 +103,7 @@ Request format: { "firstName": "John", "lastName": "Doe", - "timezone": "Americas UTC+8", - "avatarUrl": "https://github.com/.../profile.jpg", - "discord": "patrick#1234", - "teamStatus": "LOOKING_FOR_TEAM", - "description": "Lorem Ipsum…", - "interests": ["C++", "Machine Learning"] + "isVirtual": false } ``` @@ -124,13 +113,8 @@ Response format: "id": "profileid123456", "firstName": "John", "lastName": "Doe", - "points": 2021, - "timezone": "Americas UTC+8", - "avatarUrl": "https://github.com/.../profile.jpg", - "discord": "patrick#1234", - "teamStatus": "LOOKING_FOR_TEAM", - "description": "Lorem Ipsum…", - "interests": ["C++", "Machine Learning"] + "points": 0, + "isVirtual": false } ``` @@ -144,14 +128,10 @@ Note you can not edit the ``points`` field through this. Request format: ``` { + "id": "profileid123456", "firstName": "John", "lastName": "Doe", - "timezone": "Americas UTC+8", - "avatarUrl": "https://github.com/.../profile.jpg", - "discord": "patrick#1234", - "teamStatus": "LOOKING_FOR_TEAM", - "description": "Lorem Ipsum…", - "interests": ["C++", "Machine Learning"] + "isVirtual": true } ``` @@ -161,13 +141,8 @@ Response format: "id": "profileid123456", "firstName": "John", "lastName": "Doe", - "points": 2021, - "timezone": "Americas UTC+8", - "avatarUrl": "https://github.com/.../profile.jpg", - "discord": "patrick#1234", - "teamStatus": "LOOKING_FOR_TEAM", - "description": "Lorem Ipsum…", - "interests": ["C++", "Machine Learning"] + "points": 0, + "isVirtual": true } ``` @@ -186,13 +161,8 @@ Response format: "id": "profileid123456", "firstName": "John", "lastName": "Doe", - "points": 2021, - "timezone": "Americas UTC+8", - "avatarUrl": "https://github.com/.../profile.jpg", - "discord": "patrick#1234", - "teamStatus": "LOOKING_FOR_TEAM", - "description": "Lorem Ipsum…", - "interests": ["C++", "Machine Learning"] + "points": 0, + "isVirtual": false } ``` @@ -223,21 +193,13 @@ Response format: } ``` -GET /profile/search/?teamStatus=value&interests=value,value,value&limit=value +GET /profile/search/?isVirtual=value&interests=value,value,value&limit=value ------------------------- -Returns a list of profiles matching the filter conditions. - -``teamStatus`` is a string matching the user's team status. Valid values for ``teamStatus`` are ``LOOKING_FOR_MEMBERS``, ``LOOKING_FOR_TEAM``, and ``NOT_LOOKING``. - -interests is a comma-separated string representing the user's interests. - -- i.e if the user's interests are ["C++", "Machine Learning"], you can filter on this by sending ``interests="C++,Machine Learning"`` +Returns a list of profiles matching the filter conditions. If a ``limit`` parameter is provided, it will return the first matching ``limit`` profiles. Otherwise, it will return all of the matched profiles. -Any users with the TeamStatus "NOT_LOOKING" will be removed. - Response format: ``` { @@ -247,12 +209,14 @@ Response format: "firstName": "John", "lastName": "Doe", "points": 2021, + "isVirtual": false }, { "id": "profileid123456", "firstName": "John", "lastName": "Doe", "points": 2021, + "isVirtual": false }, ] } @@ -308,14 +272,8 @@ Response format: "id": "profileid123456", "firstName": "John", "lastName": "Doe", - "points": 2021, - "timezone": "Americas UTC+8", - "avatarUrl": "https://github.com/.../profile.jpg", - "discord": "patrick#1234", - "teamStatus": "LOOKING_FOR_TEAM", - "description": "Lorem Ipsum…", - "interests": ["C++", "Machine Learning"] - "points": 10 + "points": 10, + "isVirtual": false } ``` diff --git a/gateway/services/event.go b/gateway/services/event.go index 8b2317b6..194505c3 100644 --- a/gateway/services/event.go +++ b/gateway/services/event.go @@ -86,15 +86,15 @@ var EventRoutes = arbor.RouteCollection{ alice.New(middleware.AuthMiddleware([]models.Role{models.AdminRole, models.StaffRole}), middleware.IdentificationMiddleware).ThenFunc(UpdateEvent).ServeHTTP, }, arbor.Route{ - "GetEventCode", + "GetEventCodes", "GET", "/event/code/{id}/", - alice.New(middleware.AuthMiddleware([]models.Role{models.AdminRole, models.StaffRole}), middleware.IdentificationMiddleware).ThenFunc(GetEventCode).ServeHTTP, + alice.New(middleware.AuthMiddleware([]models.Role{models.AdminRole, models.StaffRole}), middleware.IdentificationMiddleware).ThenFunc(GetEventCodes).ServeHTTP, }, arbor.Route{ "UpdateEventCode", - "PUT", - "/event/code/{id}/", + "POST", + "/event/code/", alice.New(middleware.AuthMiddleware([]models.Role{models.AdminRole, models.StaffRole}), middleware.IdentificationMiddleware).ThenFunc(PutEventCode).ServeHTTP, }, arbor.Route{ @@ -122,10 +122,10 @@ func CreateEvent(w http.ResponseWriter, r *http.Request) { } func UpdateEvent(w http.ResponseWriter, r *http.Request) { - arbor.PUT(w, config.EVENT_SERVICE+r.URL.String(), EventFormat, "", r) + arbor.POST(w, config.EVENT_SERVICE+r.URL.String(), EventFormat, "", r) } -func GetEventCode(w http.ResponseWriter, r *http.Request) { +func GetEventCodes(w http.ResponseWriter, r *http.Request) { arbor.GET(w, config.EVENT_SERVICE+r.URL.String(), EventFormat, "", r) } diff --git a/gateway/services/profile.go b/gateway/services/profile.go index ad8f9ed4..efa90395 100644 --- a/gateway/services/profile.go +++ b/gateway/services/profile.go @@ -85,6 +85,12 @@ var ProfileRoutes = arbor.RouteCollection{ "/profile/favorite/", alice.New(middleware.AuthMiddleware([]models.Role{models.AdminRole, models.AttendeeRole, models.ApplicantRole, models.StaffRole, models.MentorRole}), middleware.IdentificationMiddleware).ThenFunc(RemoveProfileFavorite).ServeHTTP, }, + arbor.Route{ + "GetUserProfileByUserId", + "GET", + "/profile/user/{id}/", + alice.New(middleware.AuthMiddleware([]models.Role{models.AdminRole}), middleware.IdentificationMiddleware).ThenFunc(GetProfileByUserId).ServeHTTP, + }, // This needs to be the last route in order to prevent endpoints like "search", "leaderboard" from accidentally being routed as the {id} variable. arbor.Route{ "GetUserProfileById", @@ -102,6 +108,10 @@ func GetProfileById(w http.ResponseWriter, r *http.Request) { arbor.GET(w, config.PROFILE_SERVICE+r.URL.String(), ProfileFormat, "", r) } +func GetProfileByUserId(w http.ResponseWriter, r *http.Request) { + arbor.GET(w, config.PROFILE_SERVICE+r.URL.String(), ProfileFormat, "", r) +} + func GetValidFilteredProfiles(w http.ResponseWriter, r *http.Request) { arbor.GET(w, config.PROFILE_SERVICE+r.URL.String(), ProfileFormat, "", r) } diff --git a/services/event/controller/controller.go b/services/event/controller/controller.go index 34e55e7c..2b2dd98f 100644 --- a/services/event/controller/controller.go +++ b/services/event/controller/controller.go @@ -25,8 +25,8 @@ func SetupController(route *mux.Route) { router.HandleFunc("/", CreateEvent).Methods("POST") router.HandleFunc("/", UpdateEvent).Methods("PUT") router.HandleFunc("/", GetAllEvents).Methods("GET") - router.HandleFunc("/code/{id}/", GetEventCode).Methods("GET") - router.HandleFunc("/code/{id}/", UpdateEventCode).Methods("PUT") + router.HandleFunc("/code/{id}/", GetEventCodes).Methods("GET") + router.HandleFunc("/code/", UpsertEventCode).Methods("POST") router.HandleFunc("/checkin/", Checkin).Methods("POST") @@ -108,15 +108,32 @@ func CreateEvent(w http.ResponseWriter, r *http.Request) { json.NewDecoder(r.Body).Decode(&event) event.ID = utils.GenerateUniqueID() - var code = utils.GenerateUniqueCode() - err := service.CreateEvent(event.ID, code, event) + err := service.CreateEvent(event.ID, event) + + // It would be good to check if the error is due to failing validation (should be a 422) + // Tried using errors.Is(), but ironcally so we have a package common/errors which conflicts + // with the built-in errors package. if err != nil { errors.WriteError(w, r, errors.DatabaseError(err.Error(), "Could not create new event.")) return } + err = service.GenerateEventCode(false, event) + + if err != nil { + errors.WriteError(w, r, errors.DatabaseError(err.Error(), "Failed to create in-person code.")) + return + } + + err = service.GenerateEventCode(true, event) + + if err != nil { + errors.WriteError(w, r, errors.DatabaseError(err.Error(), "Failed to create virtual code.")) + return + } + updated_event, err := service.GetEvent(event.ID) if err != nil { @@ -154,7 +171,7 @@ func UpdateEvent(w http.ResponseWriter, r *http.Request) { /* Endpoint to get the code associated with an event (or nil) */ -func GetEventCode(w http.ResponseWriter, r *http.Request) { +func GetEventCodes(w http.ResponseWriter, r *http.Request) { id := mux.Vars(r)["id"] if id == "" { @@ -162,47 +179,38 @@ func GetEventCode(w http.ResponseWriter, r *http.Request) { return } - code, err := service.GetEventCode(id) + codes, err := service.GetEventCodes(id) if err != nil { errors.WriteError(w, r, errors.DatabaseError(err.Error(), "Failed to receive event code information from database")) return } - json.NewEncoder(w).Encode(code) + json.NewEncoder(w).Encode(codes) } /* - Endpoint to update an event code and end time + Endpoint to upsert an event code and end time */ -func UpdateEventCode(w http.ResponseWriter, r *http.Request) { - id := mux.Vars(r)["id"] - - if id == "" { - errors.WriteError(w, r, errors.MalformedRequestError("Must provide event id in request url.", "Must provide event id in request url.")) - return - } - +func UpsertEventCode(w http.ResponseWriter, r *http.Request) { var eventCode models.EventCode json.NewDecoder(r.Body).Decode(&eventCode) - eventCode.ID = id - - err := service.UpdateEventCode(id, eventCode) + err := service.UpsertEventCode(eventCode) if err != nil { errors.WriteError(w, r, errors.DatabaseError(err.Error(), "Could not update the code and timestamp of the event.")) return } - updated_event, err := service.GetEventCode(id) + updated_codes, err := service.GetEventCodes(eventCode.EventID) if err != nil { errors.WriteError(w, r, errors.DatabaseError(err.Error(), "Could not get updated event code and timestamp details.")) return } - json.NewEncoder(w).Encode(updated_event) + json.NewEncoder(w).Encode(updated_codes) } /* @@ -219,7 +227,7 @@ func Checkin(w http.ResponseWriter, r *http.Request) { var checkin_request models.CheckinRequest json.NewDecoder(r.Body).Decode(&checkin_request) - valid, event_id, err := service.CanRedeemPoints(checkin_request.Code) + valid, is_code_virtual, event_id, err := service.CanRedeemPoints(checkin_request.Code) result := models.CheckinResult{ NewPoints: -1, @@ -237,6 +245,13 @@ func Checkin(w http.ResponseWriter, r *http.Request) { return } + is_user_virtual, err := service.GetIsUserVirtual(id) + + if err != nil { + errors.WriteError(w, r, errors.UnknownError(err.Error(), "Failed to retreive if user is virtual or in-person")) + return + } + if !valid { result.Status = "InvalidTime" json.NewEncoder(w).Encode(result) @@ -264,10 +279,19 @@ func Checkin(w http.ResponseWriter, r *http.Request) { return } - result.NewPoints = event.Points + var points_to_award uint = 0 + if is_user_virtual { + points_to_award = event.VirtualPoints + } else if is_code_virtual { + points_to_award = event.InPersonVirtPoints + } else { + points_to_award = event.InPersonPoints + } + + result.NewPoints = int(points_to_award) // Add this point value to given profile - profile, err := service.AwardPoints(id, event.Points) + profile, err := service.AwardPoints(id, int(points_to_award)) if err != nil { errors.WriteError(w, r, errors.UnknownError(err.Error(), "Failed to award user with points")) diff --git a/services/event/models/event.go b/services/event/models/event.go index 7a311ab9..6e81a991 100644 --- a/services/event/models/event.go +++ b/services/event/models/event.go @@ -1,15 +1,17 @@ package models type Event struct { - ID string `json:"id" validate:"required"` - Name string `json:"name" validate:"required"` - Description string `json:"description" validate:"required"` - StartTime int64 `json:"startTime" validate:"required"` - EndTime int64 `json:"endTime" validate:"required"` - Locations []EventLocation `json:"locations" validate:"required,dive,required"` - Sponsor string `json:"sponsor"` - EventType string `json:"eventType" validate:"required,oneof=MEAL SPEAKER WORKSHOP MINIEVENT QNA OTHER"` - Points int `json:"points"` + ID string `json:"id" validate:"required"` + Name string `json:"name" validate:"required"` + Description string `json:"description" validate:"required"` + StartTime int64 `json:"startTime" validate:"required"` + EndTime int64 `json:"endTime" validate:"required"` + Locations []EventLocation `json:"locations" validate:"required,dive,required"` + Sponsor string `json:"sponsor"` + EventType string `json:"eventType" validate:"required,oneof=MEAL SPEAKER WORKSHOP MINIEVENT QNA OTHER"` + InPersonPoints uint `json:"inPersonPoints"` + InPersonVirtPoints uint `json:"inPersonVirtPoints"` + VirtualPoints uint `json:"virtualPoints"` } type EventLocation struct { diff --git a/services/event/models/event_code.go b/services/event/models/event_code.go index a9d0680a..9427073d 100644 --- a/services/event/models/event_code.go +++ b/services/event/models/event_code.go @@ -1,7 +1,8 @@ package models type EventCode struct { - ID string `json:"id"` - Code string `json:"code"` - Expiration int64 `json:"expiration"` + CodeID string `json:"codeID" validate:"required"` + EventID string `json:"eventID" validate:"required"` + IsVirtual bool `json:"isVirtual" validate:"required"` + Expiration int64 `json:"expiration" validate:"required"` } diff --git a/services/event/service/event_service.go b/services/event/service/event_service.go index 0c6b4392..45af3d56 100644 --- a/services/event/service/event_service.go +++ b/services/event/service/event_service.go @@ -147,7 +147,7 @@ func GetFilteredEvents(parameters map[string][]string) (*models.EventList, error /* Creates an event with the given id */ -func CreateEvent(id string, code string, event models.Event) error { +func CreateEvent(id string, event models.Event) error { err := validate.Struct(event) if err != nil { @@ -176,18 +176,6 @@ func CreateEvent(id string, code string, event models.Event) error { err = db.Insert("eventtrackers", &event_tracker) - if err != nil { - return err - } - - event_code := models.EventCode{ - ID: id, - Code: code, - Expiration: event.EndTime, - } - - err = db.Insert("eventcodes", &event_code) - return err } @@ -478,51 +466,100 @@ func GetStats() (map[string]interface{}, error) { Check if an event can be redeemed for points, i.e., that the point timeout has not been reached Returns true if the current time is between `PreEventCheckinIntervalInMinutes` number of minutes before the event, and the end of event. */ -func CanRedeemPoints(event_code string) (bool, string, error) { +func CanRedeemPoints(event_code string) (bool, bool, string, error) { query := database.QuerySelector{ - "code": event_code, + "codeid": event_code, } var eventCode models.EventCode err := db.FindOne("eventcodes", query, &eventCode) if err != nil { - return false, "invalid", err + return false, false, "invalid", err } expiration_time := eventCode.Expiration current_time := time.Now().Unix() - return current_time < expiration_time, eventCode.ID, nil + return current_time < expiration_time, eventCode.IsVirtual, eventCode.EventID, nil } /* Returns the eventcode struct for the event with the given id */ -func GetEventCode(id string) (*models.EventCode, error) { +func GetEventCodes(id string) (*[]models.EventCode, error) { query := database.QuerySelector{ - "id": id, + "eventid": id, } - var eventCode models.EventCode - err := db.FindOne("eventcodes", query, &eventCode) + eventCodes := []models.EventCode{} + + err := db.FindAll("eventcodes", query, &eventCodes) if err != nil { return nil, err } - return &eventCode, nil + return &eventCodes, nil } /* - Updates the event code and end time with the given id + Upserts the event code and end time with the given id + If no matching code is found, then it is a new code and add it */ -func UpdateEventCode(id string, eventCode models.EventCode) error { +func UpsertEventCode(eventCode models.EventCode) error { + err := validate.Struct(eventCode) + + if err != nil { + return err + } + selector := database.QuerySelector{ - "id": id, + "codeid": eventCode.CodeID, } - err := db.Update("eventcodes", selector, &eventCode) + _, err = db.Upsert("eventcodes", selector, &eventCode) return err } + +func GenerateEventCode(isVirtual bool, event models.Event) error { + // The probability of a generated code colliding with an existing + // code is (N / 2^24) where N is the number of existing codes. + // We will attempt to insert the row 10 times each with a new random + // code, making the success rate 1 - ((N / 2^24)^10) + var code string + + for i := 0; i < 10; i++ { + code = utils.GenerateUniqueCode() + + query := database.QuerySelector{ + "codeid": code, + } + + err := db.FindOne("eventcodes", query, models.EventCode{}) + + if err == database.ErrNotFound { + eventCode := models.EventCode{ + CodeID: code, + EventID: event.ID, + IsVirtual: isVirtual, + Expiration: event.EndTime, + } + + err = db.Insert("eventcodes", &eventCode) + + return err + } + } + + err_str := "Failed to generate a unique " + + if isVirtual { + err_str += "virtual event code." + } else { + err_str += "in-person event code." + } + + return errors.New(err_str) +} diff --git a/services/event/service/profile_service.go b/services/event/service/profile_service.go index 0333c762..0f7adab5 100644 --- a/services/event/service/profile_service.go +++ b/services/event/service/profile_service.go @@ -53,3 +53,19 @@ func AwardPoints(id string, points int) (*models.Profile, error) { return &profile, nil } + +func GetIsUserVirtual(id string) (bool, error) { + var profile models.Profile + + status, err := apirequest.Get(config.PROFILE_SERVICE+"/profile/user/"+id+"/", &profile) + + if err != nil { + return false, err + } + + if status != http.StatusOK { + return false, errors.New("Unable to retrieve if user is virtual or in-person") + } + + return profile.IsVirtual, nil +} diff --git a/services/event/tests/event_test.go b/services/event/tests/event_test.go index 4b2e12f6..ad69619b 100644 --- a/services/event/tests/event_test.go +++ b/services/event/tests/event_test.go @@ -66,7 +66,9 @@ func SetupTestDB(t *testing.T) { Longitude: 123.456, }, }, - Points: 10, + InPersonPoints: 10, + InPersonVirtPoints: 7, + VirtualPoints: 5, } err := db.Insert("events", &event) @@ -153,7 +155,9 @@ func TestGetAllEventsService(t *testing.T) { Longitude: 123.456, }, }, - Points: 10, + InPersonPoints: 10, + InPersonVirtPoints: 7, + VirtualPoints: 5, }, { ID: "testid2", @@ -172,7 +176,9 @@ func TestGetAllEventsService(t *testing.T) { Longitude: 123.456, }, }, - Points: 0, + InPersonPoints: 0, + InPersonVirtPoints: 0, + VirtualPoints: 0, }, }, } @@ -224,7 +230,9 @@ func TestGetFilteredEventsService(t *testing.T) { Longitude: 123.456, }, }, - Points: 0, + InPersonPoints: 0, + InPersonVirtPoints: 0, + VirtualPoints: 0, } err := db.Insert("events", &event) @@ -262,7 +270,9 @@ func TestGetFilteredEventsService(t *testing.T) { Longitude: 123.456, }, }, - Points: 0, + InPersonPoints: 0, + InPersonVirtPoints: 0, + VirtualPoints: 0, }, }, } @@ -300,7 +310,9 @@ func TestGetFilteredEventsService(t *testing.T) { Longitude: 123.456, }, }, - Points: 10, + InPersonPoints: 10, + InPersonVirtPoints: 7, + VirtualPoints: 5, }, { ID: "testid2", @@ -319,7 +331,9 @@ func TestGetFilteredEventsService(t *testing.T) { Longitude: 123.456, }, }, - Points: 0, + InPersonPoints: 0, + InPersonVirtPoints: 0, + VirtualPoints: 0, }, }, } @@ -377,7 +391,9 @@ func TestGetEventService(t *testing.T) { Longitude: 123.456, }, }, - Points: 10, + InPersonPoints: 10, + InPersonVirtPoints: 7, + VirtualPoints: 5, } if !reflect.DeepEqual(event, &expected_event) { @@ -411,7 +427,7 @@ func TestCreateEventService(t *testing.T) { }, } - err := service.CreateEvent("testid2", "testcode2", new_event) + err := service.CreateEvent("testid2", new_event) if err != nil { t.Fatal(err) @@ -439,7 +455,9 @@ func TestCreateEventService(t *testing.T) { Longitude: 123.456, }, }, - Points: 0, + InPersonPoints: 0, + InPersonVirtPoints: 0, + VirtualPoints: 0, } if !reflect.DeepEqual(event, &expected_event) { @@ -536,7 +554,9 @@ func TestUpdateEventService(t *testing.T) { Longitude: 123.456, }, }, - Points: 100, + InPersonPoints: 100, + InPersonVirtPoints: 70, + VirtualPoints: 50, } err := service.UpdateEvent("testid", event) @@ -567,7 +587,9 @@ func TestUpdateEventService(t *testing.T) { Longitude: 123.456, }, }, - Points: 100, + InPersonPoints: 100, + InPersonVirtPoints: 70, + VirtualPoints: 50, } if !reflect.DeepEqual(updated_event, &expected_event) { @@ -700,7 +722,7 @@ func TestIsEventActive(t *testing.T) { }, } - service.CreateEvent(new_event.ID, "testcode3", new_event) + service.CreateEvent(new_event.ID, new_event) is_active, err := service.IsEventActive("testid3") @@ -719,7 +741,7 @@ func TestIsEventActive(t *testing.T) { new_event.StartTime = TestTime new_event.EndTime = TestTime + ONE_MINUTE_IN_SECONDS*20 - service.CreateEvent(new_event.ID, "testcode4", new_event) + service.CreateEvent(new_event.ID, new_event) is_active, err = service.IsEventActive("testid4") @@ -824,3 +846,238 @@ func TestRemoveEventFavorite(t *testing.T) { CleanupTestDB(t) } + +/* + Tests event code generation for a given event id +*/ +func TestGenerateEventCode(t *testing.T) { + SetupTestDB(t) + + event, err := service.GetEvent("testid") + + if err != nil { + t.Fatal(err) + } + + err = service.GenerateEventCode(false, *event) + + if err != nil { + t.Fatal(err) + } + + query := database.QuerySelector{ + "eventid": event.ID, + } + + event_codes := []models.EventCode{} + + err = db.FindAll("eventcodes", query, &event_codes) + + if err != nil { + t.Fatal(err) + } + + expected_event_codes := []models.EventCode{ + { + CodeID: "some random code that's gonna get replaced here", + EventID: event.ID, + IsVirtual: false, + Expiration: event.EndTime, + }, + } + + for i, code := range event_codes { + expected_event_codes[i].CodeID = code.CodeID + } + + if !reflect.DeepEqual(&event_codes, &expected_event_codes) { + t.Errorf("Wrong event codes. Expected %v, got %v", &expected_event_codes, &event_codes) + } + + CleanupTestDB(t) +} + +/* + Tests updating an event code +*/ +func TestUpdateEventCode(t *testing.T) { + SetupTestDB(t) + + event_code := models.EventCode{ + CodeID: "abcdef", + EventID: "testid", + IsVirtual: false, + Expiration: 3133535820, + } + + err := db.Insert("eventcodes", &event_code) + + if err != nil { + t.Fatal(err) + } + + event_code.IsVirtual = true + event_code.Expiration = 1609735934 + + err = service.UpsertEventCode(event_code) + + if err != nil { + t.Fatal(err) + } + + query := database.QuerySelector{ + "eventid": "testid", + } + + event_codes := []models.EventCode{} + + err = db.FindAll("eventcodes", query, &event_codes) + + if err != nil { + t.Fatal(err) + } + + expected_event_codes := []models.EventCode{ + { + CodeID: "abcdef", + EventID: "testid", + IsVirtual: true, + Expiration: 1609735934, + }, + } + + if !reflect.DeepEqual(&event_codes, &expected_event_codes) { + t.Errorf("Wrong event codes. Expected %v, got %v", &expected_event_codes, &event_codes) + } + + CleanupTestDB(t) +} + +/* + Tests inserting a new event code +*/ +func TestInsertEventCode(t *testing.T) { + SetupTestDB(t) + + event_code_1 := models.EventCode{ + CodeID: "abcdef", + EventID: "testid", + IsVirtual: false, + Expiration: 3133535820, + } + + err := db.Insert("eventcodes", &event_code_1) + + if err != nil { + t.Fatal(err) + } + + event_code_2 := models.EventCode{ + CodeID: "123456", + EventID: "testid", + IsVirtual: true, + Expiration: 3133535820, + } + + event_code_1.IsVirtual = true + event_code_1.Expiration = 1609735934 + + err = service.UpsertEventCode(event_code_2) + + if err != nil { + t.Fatal(err) + } + + query := database.QuerySelector{ + "eventid": "testid", + } + + event_codes := []models.EventCode{} + + err = db.FindAll("eventcodes", query, &event_codes) + + if err != nil { + t.Fatal(err) + } + + expected_event_codes := []models.EventCode{ + { + CodeID: "abcdef", + EventID: "testid", + IsVirtual: false, + Expiration: 3133535820, + }, + { + CodeID: "123456", + EventID: "testid", + IsVirtual: true, + Expiration: 3133535820, + }, + } + + if !reflect.DeepEqual(&event_codes, &expected_event_codes) { + t.Errorf("Wrong event codes. Expected %v, got %v", &expected_event_codes, &event_codes) + } + + CleanupTestDB(t) +} + +/* + Tests getting all event codes for a given event id +*/ +func TestGetEventCodes(t *testing.T) { + SetupTestDB(t) + + event_code_1 := models.EventCode{ + CodeID: "abcdef", + EventID: "testid", + IsVirtual: false, + Expiration: 3133535820, + } + + event_code_2 := models.EventCode{ + CodeID: "123456", + EventID: "testid", + IsVirtual: true, + Expiration: 3133535820, + } + + err := db.Insert("eventcodes", &event_code_1) + + if err != nil { + t.Fatal(err) + } + + err = db.Insert("eventcodes", &event_code_2) + + if err != nil { + t.Fatal(err) + } + + event_codes, err := service.GetEventCodes("testid") + + if err != nil { + t.Fatal(err) + } + + expected_event_codes := []models.EventCode{ + { + CodeID: "abcdef", + EventID: "testid", + IsVirtual: false, + Expiration: 3133535820, + }, + { + CodeID: "123456", + EventID: "testid", + IsVirtual: true, + Expiration: 3133535820, + }, + } + + if !reflect.DeepEqual(event_codes, &expected_event_codes) { + t.Errorf("Wrong event codes. Expected %v, got %v", &expected_event_codes, &event_codes) + } + + CleanupTestDB(t) +} diff --git a/services/profile/controller/controller.go b/services/profile/controller/controller.go index 7e16060b..04480d7e 100644 --- a/services/profile/controller/controller.go +++ b/services/profile/controller/controller.go @@ -30,6 +30,8 @@ func SetupController(route *mux.Route) { router.HandleFunc("/favorite/", AddProfileFavorite).Methods("POST") router.HandleFunc("/favorite/", RemoveProfileFavorite).Methods("DELETE") + router.HandleFunc("/user/{id}/", GetProfileByUserId).Methods("GET") + router.HandleFunc("/{id}/", GetProfileById).Methods("GET") } @@ -72,6 +74,29 @@ func GetProfileById(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(user_profile) } +/* + GetProfileByUserId is used to get a profile for a provided user id. +*/ +func GetProfileByUserId(w http.ResponseWriter, r *http.Request) { + user_id := mux.Vars(r)["id"] + + profile_id, err := service.GetProfileIdFromUserId(user_id) + + if err != nil { + errors.WriteError(w, r, errors.DatabaseError(err.Error(), "Could not get profile id associated with the user id "+user_id)) + return + } + + user_profile, err := service.GetProfile(profile_id) + + if err != nil { + errors.WriteError(w, r, errors.DatabaseError(err.Error(), "Could not get profile for user id "+user_id)) + return + } + + json.NewEncoder(w).Encode(user_profile) +} + /* CreateProfile is the endpoint to create the profile for the current user. */ diff --git a/services/profile/models/profile.go b/services/profile/models/profile.go index 9db48172..520de24b 100644 --- a/services/profile/models/profile.go +++ b/services/profile/models/profile.go @@ -1,14 +1,9 @@ package models type Profile struct { - ID string `json:"id"` - FirstName string `json:"firstName"` - LastName string `json:"lastName"` - Points int `json:"points"` - Timezone string `json:"timezone"` - Description string `json:"description"` - Discord string `json:"discord"` - AvatarUrl string `json:"avatarUrl"` - TeamStatus string `json:"teamStatus"` - Interests []string `json:"interests"` + ID string `json:"id"` + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + Points int `json:"points"` + IsVirtual bool `json:"isVirtual"` } diff --git a/services/profile/service/profile_service.go b/services/profile/service/profile_service.go index 38b685c2..62fd3f24 100644 --- a/services/profile/service/profile_service.go +++ b/services/profile/service/profile_service.go @@ -295,9 +295,10 @@ func GetFilteredProfiles(parameters map[string][]string) (*models.ProfileList, e /* Returns a list of profiles filtered upon teamStatus and interests. Will be limited to only include the first "limit" results. Will also remove profiles with a TeamStatus set to "NOT_LOOKING" + + Sorta redundant since the Profile model doesn't have team status or interest fields anymore */ func GetValidFilteredProfiles(parameters map[string][]string) (*models.ProfileList, error) { - parameters["teamStatusNot"] = append(parameters["teamStatusNot"], "NOT_LOOKING") filtered_profile_list, err := GetFilteredProfiles(parameters) if err != nil { @@ -323,10 +324,11 @@ func RedeemEvent(profile_id string, event_id string) (*models.RedeemEventRespons if err != nil { if err == database.ErrNotFound { - err = db.Insert("profileattendance", &models.AttendanceTracker{ + attended_events = models.AttendanceTracker{ ID: profile_id, Events: []string{}, - }) + } + err = db.Insert("profileattendance", &attended_events) if err != nil { redemption_status.Status = "Could not add tracker to db" diff --git a/services/profile/tests/profile_test.go b/services/profile/tests/profile_test.go index fe933518..df8be867 100644 --- a/services/profile/tests/profile_test.go +++ b/services/profile/tests/profile_test.go @@ -53,16 +53,11 @@ func SetupTestDB(t *testing.T) { profile_id := "testid" profile := models.Profile{ - ID: profile_id, - FirstName: "testfirstname", - LastName: "testlastname", - Points: 0, - Timezone: "America/Chicago", - Description: "Hi", - Discord: "testdiscordusername", - AvatarUrl: "https://imgs.smoothradio.com/images/191589?crop=16_9&width=660&relax=1&signature=Rz93ikqcAz7BcX6SKiEC94zJnqo=", - TeamStatus: "LOOKING_FOR_TEAM", - Interests: []string{"testinterest1", "testinterest2"}, + ID: profile_id, + FirstName: "testfirstname", + LastName: "testlastname", + Points: 0, + IsVirtual: false, } id_map := models.IdMap{ @@ -121,18 +116,14 @@ func CleanupTestDB(t *testing.T) { */ func TestGetAllProfilesService(t *testing.T) { SetupTestDB(t) + defer CleanupTestDB(t) profile := models.Profile{ - ID: "testid2", - FirstName: "testfirstname2", - LastName: "testlastname2", - Points: 340, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername2", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"testinterest2"}, + ID: "testid2", + FirstName: "testfirstname2", + LastName: "testlastname2", + Points: 340, + IsVirtual: true, } err := db.Insert("profiles", &profile) @@ -152,28 +143,18 @@ func TestGetAllProfilesService(t *testing.T) { expected_profile_list := models.ProfileList{ Profiles: []models.Profile{ { - ID: "testid", - FirstName: "testfirstname", - LastName: "testlastname", - Points: 0, - Timezone: "America/Chicago", - Description: "Hi", - Discord: "testdiscordusername", - AvatarUrl: "https://imgs.smoothradio.com/images/191589?crop=16_9&width=660&relax=1&signature=Rz93ikqcAz7BcX6SKiEC94zJnqo=", - TeamStatus: "LOOKING_FOR_TEAM", - Interests: []string{"testinterest1", "testinterest2"}, + ID: "testid", + FirstName: "testfirstname", + LastName: "testlastname", + Points: 0, + IsVirtual: false, }, { - ID: "testid2", - FirstName: "testfirstname2", - LastName: "testlastname2", - Points: 340, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername2", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"testinterest2"}, + ID: "testid2", + FirstName: "testfirstname2", + LastName: "testlastname2", + Points: 340, + IsVirtual: true, }, }, } @@ -197,9 +178,6 @@ func TestGetAllProfilesService(t *testing.T) { if !reflect.DeepEqual(actual_profile_list, &expected_profile_list) { t.Errorf("Wrong profile list. Expected %v, got %v", expected_profile_list, actual_profile_list) } - - CleanupTestDB(t) - } /* @@ -207,6 +185,7 @@ func TestGetAllProfilesService(t *testing.T) { */ func TestGetProfileService(t *testing.T) { SetupTestDB(t) + defer CleanupTestDB(t) profile, err := service.GetProfile("testid") @@ -215,23 +194,16 @@ func TestGetProfileService(t *testing.T) { } expected_profile := models.Profile{ - ID: "testid", - FirstName: "testfirstname", - LastName: "testlastname", - Points: 0, - Timezone: "America/Chicago", - Description: "Hi", - Discord: "testdiscordusername", - AvatarUrl: "https://imgs.smoothradio.com/images/191589?crop=16_9&width=660&relax=1&signature=Rz93ikqcAz7BcX6SKiEC94zJnqo=", - TeamStatus: "LOOKING_FOR_TEAM", - Interests: []string{"testinterest1", "testinterest2"}, + ID: "testid", + FirstName: "testfirstname", + LastName: "testlastname", + Points: 0, + IsVirtual: false, } if !reflect.DeepEqual(profile, &expected_profile) { t.Errorf("Wrong profile info. Expected %v, got %v", &expected_profile, profile) } - - CleanupTestDB(t) } /* @@ -239,18 +211,14 @@ func TestGetProfileService(t *testing.T) { */ func TestCreateProfileService(t *testing.T) { SetupTestDB(t) + defer CleanupTestDB(t) new_profile := models.Profile{ - ID: "testid2", - FirstName: "testfirstname2", - LastName: "testlastname2", - Points: 340, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername2", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"testinterest2"}, + ID: "testid2", + FirstName: "testfirstname2", + LastName: "testlastname2", + Points: 340, + IsVirtual: true, } err := service.CreateProfile("testuserid2", "testid2", new_profile) @@ -266,16 +234,11 @@ func TestCreateProfileService(t *testing.T) { } expected_profile := models.Profile{ - ID: "testid2", - FirstName: "testfirstname2", - LastName: "testlastname2", - Points: 340, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername2", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"testinterest2"}, + ID: "testid2", + FirstName: "testfirstname2", + LastName: "testlastname2", + Points: 340, + IsVirtual: true, } if !reflect.DeepEqual(profile, &expected_profile) { @@ -292,8 +255,6 @@ func TestCreateProfileService(t *testing.T) { if profile_id1 != "testid2" { t.Errorf("Wrong profile mapping found for user %s. Expected %s but got %s", "testuserid2", "testid2", profile_id1) } - - CleanupTestDB(t) } /* @@ -301,6 +262,7 @@ func TestCreateProfileService(t *testing.T) { */ func TestDeleteProfileService(t *testing.T) { SetupTestDB(t) + defer CleanupTestDB(t) profile_id := "testid" @@ -318,8 +280,6 @@ func TestDeleteProfileService(t *testing.T) { if err == nil { t.Errorf("Found profile %v in profiles database.", profile) } - - CleanupTestDB(t) } /* @@ -327,18 +287,14 @@ func TestDeleteProfileService(t *testing.T) { */ func TestUpdateProfileService(t *testing.T) { SetupTestDB(t) + defer CleanupTestDB(t) profile := models.Profile{ - ID: "testid", - FirstName: "testfirstname2", - LastName: "testlastname2", - Points: 340, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername2", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"testinterest2"}, + ID: "testid", + FirstName: "testfirstname2", + LastName: "testlastname2", + Points: 340, + IsVirtual: true, } err := service.UpdateProfile("testid", profile) @@ -354,61 +310,44 @@ func TestUpdateProfileService(t *testing.T) { } expected_profile := models.Profile{ - ID: "testid", - FirstName: "testfirstname2", - LastName: "testlastname2", - Points: 340, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername2", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"testinterest2"}, + ID: "testid", + FirstName: "testfirstname2", + LastName: "testlastname2", + Points: 340, + IsVirtual: true, } if !reflect.DeepEqual(updated_profile, &expected_profile) { t.Errorf("Wrong profile info. Expected %v, got %v", expected_profile, updated_profile) } - - CleanupTestDB(t) } func TestGetFilteredProfiles(t *testing.T) { SetupTestDB(t) + defer CleanupTestDB(t) profile := models.Profile{ - ID: "testid2", - FirstName: "testfirstname2", - LastName: "testlastname2", - Points: 340, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername2", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"Cpp", "Machine Learning", "Additional Interest"}, + ID: "testid2", + FirstName: "testfirstname2", + LastName: "testlastname2", + Points: 340, + IsVirtual: true, } err := db.Insert("profiles", &profile) profile = models.Profile{ - ID: "testid3", - FirstName: "testfirstname3", - LastName: "testlastname3", - Points: 342, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername3", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"Cpp", "Machine Learning"}, + ID: "testid3", + FirstName: "testfirstname3", + LastName: "testlastname3", + Points: 342, + IsVirtual: true, } err = db.Insert("profiles", &profile) parameters := map[string][]string{ - "teamStatus": {"NOT_LOOKING"}, - "interests": {"Cpp,Machine Learning"}, - "limit": {"0"}, + "IsVirtual": {"true"}, + "limit": {"0"}, } filtered_profile_list, err := service.GetFilteredProfiles(parameters) @@ -420,28 +359,18 @@ func TestGetFilteredProfiles(t *testing.T) { expected_filtered_profile_list := models.ProfileList{ Profiles: []models.Profile{ { - ID: "testid2", - FirstName: "testfirstname2", - LastName: "testlastname2", - Points: 340, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername2", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"Cpp", "Machine Learning", "Additional Interest"}, + ID: "testid2", + FirstName: "testfirstname2", + LastName: "testlastname2", + Points: 340, + IsVirtual: true, }, { - ID: "testid3", - FirstName: "testfirstname3", - LastName: "testlastname3", - Points: 342, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername3", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"Cpp", "Machine Learning"}, + ID: "testid3", + FirstName: "testfirstname3", + LastName: "testlastname3", + Points: 342, + IsVirtual: true, }, }, } @@ -452,9 +381,8 @@ func TestGetFilteredProfiles(t *testing.T) { // Add a limit and test that parameters = map[string][]string{ - "teamStatus": {"NOT_LOOKING"}, - "interests": {"Cpp,Machine Learning"}, - "limit": {"1"}, + "IsVirtual": {"true"}, + "limit": {"1"}, } filtered_profile_list, err = service.GetFilteredProfiles(parameters) @@ -462,46 +390,11 @@ func TestGetFilteredProfiles(t *testing.T) { expected_filtered_profile_list = models.ProfileList{ Profiles: []models.Profile{ { - ID: "testid2", - FirstName: "testfirstname2", - LastName: "testlastname2", - Points: 340, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername2", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"Cpp", "Machine Learning", "Additional Interest"}, - }, - }, - } - - if !reflect.DeepEqual(filtered_profile_list, &expected_filtered_profile_list) { - t.Errorf("Wrong profile list. Expected %v, got %v", expected_filtered_profile_list, filtered_profile_list) - } - - // Change the interests to be off by one - parameters = map[string][]string{ - "teamStatus": {"NOT_LOOKING"}, - "interests": {"Cpp,Machine Learning,Additional Interest"}, - "limit": {"0"}, - } - - filtered_profile_list, err = service.GetFilteredProfiles(parameters) - - expected_filtered_profile_list = models.ProfileList{ - Profiles: []models.Profile{ - { - ID: "testid2", - FirstName: "testfirstname2", - LastName: "testlastname2", - Points: 340, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername2", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"Cpp", "Machine Learning", "Additional Interest"}, + ID: "testid2", + FirstName: "testfirstname2", + LastName: "testlastname2", + Points: 340, + IsVirtual: true, }, }, } @@ -510,10 +403,9 @@ func TestGetFilteredProfiles(t *testing.T) { t.Errorf("Wrong profile list. Expected %v, got %v", expected_filtered_profile_list, filtered_profile_list) } - // Remove filter by interests + // Remove filter by virtual status parameters = map[string][]string{ - "teamStatus": {"NOT_LOOKING"}, - "limit": {"0"}, + "limit": {"0"}, } filtered_profile_list, err = service.GetFilteredProfiles(parameters) @@ -521,57 +413,25 @@ func TestGetFilteredProfiles(t *testing.T) { expected_filtered_profile_list = models.ProfileList{ Profiles: []models.Profile{ { - ID: "testid2", - FirstName: "testfirstname2", - LastName: "testlastname2", - Points: 340, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername2", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"Cpp", "Machine Learning", "Additional Interest"}, + ID: "testid", + FirstName: "testfirstname", + LastName: "testlastname", + Points: 0, + IsVirtual: false, }, { - ID: "testid3", - FirstName: "testfirstname3", - LastName: "testlastname3", - Points: 342, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername3", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"Cpp", "Machine Learning"}, + ID: "testid2", + FirstName: "testfirstname2", + LastName: "testlastname2", + Points: 340, + IsVirtual: true, }, - }, - } - - if !reflect.DeepEqual(filtered_profile_list, &expected_filtered_profile_list) { - t.Errorf("Wrong profile list. Expected %v, got %v", expected_filtered_profile_list, filtered_profile_list) - } - - // Remove filter by teamStatus - parameters = map[string][]string{ - "interests": {"Cpp,Machine Learning,Additional Interest"}, - "limit": {"0"}, - } - - filtered_profile_list, err = service.GetFilteredProfiles(parameters) - - expected_filtered_profile_list = models.ProfileList{ - Profiles: []models.Profile{ { - ID: "testid2", - FirstName: "testfirstname2", - LastName: "testlastname2", - Points: 340, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername2", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"Cpp", "Machine Learning", "Additional Interest"}, + ID: "testid3", + FirstName: "testfirstname3", + LastName: "testlastname3", + Points: 342, + IsVirtual: true, }, }, } @@ -579,24 +439,18 @@ func TestGetFilteredProfiles(t *testing.T) { if !reflect.DeepEqual(filtered_profile_list, &expected_filtered_profile_list) { t.Errorf("Wrong profile list. Expected %v, got %v", expected_filtered_profile_list, filtered_profile_list) } - - CleanupTestDB(t) } func TestGetProfileLeaderboard(t *testing.T) { SetupTestDB(t) + defer CleanupTestDB(t) profile := models.Profile{ - ID: "testid2", - FirstName: "testfirstname2", - LastName: "testlastname2", - Points: 340, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername2", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"Cpp", "Machine Learning", "Additional Interest"}, + ID: "testid2", + FirstName: "testfirstname2", + LastName: "testlastname2", + Points: 340, + IsVirtual: true, } err := db.Insert("profiles", &profile) @@ -636,16 +490,11 @@ func TestGetProfileLeaderboard(t *testing.T) { // Insert another profile and test profile = models.Profile{ - ID: "testid3", - FirstName: "testfirstname3", - LastName: "testlastname3", - Points: 999, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername3", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"Cpp"}, + ID: "testid3", + FirstName: "testfirstname3", + LastName: "testlastname3", + Points: 999, + IsVirtual: true, } err = db.Insert("profiles", &profile) @@ -720,44 +569,33 @@ func TestGetProfileLeaderboard(t *testing.T) { if !reflect.DeepEqual(leaderboard, &expected_leaderboard) { t.Errorf("Wrong profile info. Expected %v, got %v", expected_leaderboard, leaderboard) } - - CleanupTestDB(t) } func TestGetValidFilteredProfiles(t *testing.T) { SetupTestDB(t) + defer CleanupTestDB(t) profile := models.Profile{ - ID: "testid2", - FirstName: "testfirstname2", - LastName: "testlastname2", - Points: 340, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername2", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"Cpp", "Machine Learning", "Additional Interest"}, + ID: "testid2", + FirstName: "testfirstname2", + LastName: "testlastname2", + Points: 340, + IsVirtual: false, } err := db.Insert("profiles", &profile) profile = models.Profile{ - ID: "testid3", - FirstName: "testfirstname3", - LastName: "testlastname3", - Points: 342, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername3", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"Cpp", "Machine Learning"}, + ID: "testid3", + FirstName: "testfirstname3", + LastName: "testlastname3", + Points: 342, + IsVirtual: true, } err = db.Insert("profiles", &profile) parameters := map[string][]string{ - "interests": {"Cpp,Machine Learning"}, + "IsVirtual": {"true"}, "limit": {"0"}, } @@ -770,35 +608,29 @@ func TestGetValidFilteredProfiles(t *testing.T) { expected_filtered_profile_list := models.ProfileList{ Profiles: []models.Profile{ { - ID: "testid3", - FirstName: "testfirstname3", - LastName: "testlastname3", - Points: 342, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername3", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "NOT_LOOKING", - Interests: []string{"Cpp", "Machine Learning"}, + ID: "testid3", + FirstName: "testfirstname3", + LastName: "testlastname3", + Points: 342, + IsVirtual: true, }, }, } + if !reflect.DeepEqual(filtered_profile_list, &expected_filtered_profile_list) { + t.Errorf("Wrong profile list. Expected %v, got %v", expected_filtered_profile_list, filtered_profile_list) + } + profile = models.Profile{ - ID: "testid4", - FirstName: "testfirstname3", - LastName: "testlastname3", - Points: 342, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername3", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "LOOKING_FOR_TEAM", - Interests: []string{}, + ID: "testid4", + FirstName: "testfirstname4", + LastName: "testlastname4", + Points: 342, + IsVirtual: false, } err = db.Insert("profiles", &profile) - // Remove the interests filter. Now every profile should show up except for those that are "NOT_LOOKING" for a team. + // Remove the virtual status filter. Now every profile should show up. parameters = map[string][]string{ "limit": {"0"}, @@ -813,98 +645,50 @@ func TestGetValidFilteredProfiles(t *testing.T) { expected_filtered_profile_list = models.ProfileList{ Profiles: []models.Profile{ { - ID: "testid", - FirstName: "testfirstname", - LastName: "testlastname", - Points: 0, - Timezone: "America/Chicago", - Description: "Hi", - Discord: "testdiscordusername", - AvatarUrl: "https://imgs.smoothradio.com/images/191589?crop=16_9&width=660&relax=1&signature=Rz93ikqcAz7BcX6SKiEC94zJnqo=", - TeamStatus: "LOOKING_FOR_TEAM", - Interests: []string{"testinterest1", "testinterest2"}, + ID: "testid", + FirstName: "testfirstname", + LastName: "testlastname", + Points: 0, + IsVirtual: false, }, { - ID: "testid4", - FirstName: "testfirstname3", - LastName: "testlastname3", - Points: 342, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername3", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "LOOKING_FOR_TEAM", - Interests: []string{}, + ID: "testid2", + FirstName: "testfirstname2", + LastName: "testlastname2", + Points: 340, + IsVirtual: false, }, - }, - } - if !reflect.DeepEqual(filtered_profile_list, &expected_filtered_profile_list) { - t.Errorf("Wrong profile list. Expected %v, got %v", expected_filtered_profile_list, filtered_profile_list) - } - - // Add a TeamStatus filter. - - parameters = map[string][]string{ - "teamStatus": {"LOOKING_FOR_TEAM"}, - "limit": {"0"}, - } - - filtered_profile_list, err = service.GetValidFilteredProfiles(parameters) - - if err != nil { - t.Fatal(err) - } - - expected_filtered_profile_list = models.ProfileList{ - Profiles: []models.Profile{ { - ID: "testid", - FirstName: "testfirstname", - LastName: "testlastname", - Points: 0, - Timezone: "America/Chicago", - Description: "Hi", - Discord: "testdiscordusername", - AvatarUrl: "https://imgs.smoothradio.com/images/191589?crop=16_9&width=660&relax=1&signature=Rz93ikqcAz7BcX6SKiEC94zJnqo=", - TeamStatus: "LOOKING_FOR_TEAM", - Interests: []string{"testinterest1", "testinterest2"}, + ID: "testid3", + FirstName: "testfirstname3", + LastName: "testlastname3", + Points: 342, + IsVirtual: true, }, { - ID: "testid4", - FirstName: "testfirstname3", - LastName: "testlastname3", - Points: 342, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername3", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "LOOKING_FOR_TEAM", - Interests: []string{}, + ID: "testid4", + FirstName: "testfirstname4", + LastName: "testlastname4", + Points: 342, + IsVirtual: false, }, }, } - if !reflect.DeepEqual(filtered_profile_list, &expected_filtered_profile_list) { t.Errorf("Wrong profile list. Expected %v, got %v", expected_filtered_profile_list, filtered_profile_list) } - - CleanupTestDB(t) } func TestProfileFavorites(t *testing.T) { SetupTestDB(t) + defer CleanupTestDB(t) profile := models.Profile{ - ID: "testid2", - FirstName: "testfirstname2", - LastName: "testlastname2", - Points: 340, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername2", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "Not Looking", - Interests: []string{"Cpp", "Machine Learning", "Additional Interest"}, + ID: "testid2", + FirstName: "testfirstname2", + LastName: "testlastname2", + Points: 340, + IsVirtual: true, } err := db.Insert("profiles", &profile) @@ -967,16 +751,11 @@ func TestProfileFavorites(t *testing.T) { // Favorite another profile profile = models.Profile{ - ID: "testid3", - FirstName: "testfirstname3", - LastName: "testlastname3", - Points: 342, - Timezone: "America/New York", - Description: "Hello", - Discord: "testdiscordusername3", - AvatarUrl: "https://yt3.ggpht.com/ytc/AAUvwniHNhQyp4hWj3nrADnils-6N3jNREP8rWKGDTp0Lg=s900-c-k-c0x00ffffff-no-rj", - TeamStatus: "Found Team", - Interests: []string{"Cpp", "Machine Learning"}, + ID: "testid3", + FirstName: "testfirstname3", + LastName: "testlastname3", + Points: 342, + IsVirtual: true, } err = db.Insert("profiles", &profile) if err != nil { @@ -1013,6 +792,4 @@ func TestProfileFavorites(t *testing.T) { if !reflect.DeepEqual(profile_favorites, &expected_profile_favorites) { t.Errorf("Wrong favorite profile list. Expected %v, got %v", expected_profile_favorites, profile_favorites) } - - CleanupTestDB(t) }