Skip to content
This repository was archived by the owner on Dec 7, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions common/database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type Database interface {
RemoveAll(collection_name string, query interface{}) (*ChangeResults, error)
Insert(collection_name string, item interface{}) error
Upsert(collection_name string, selector interface{}, update interface{}) (*ChangeResults, error)
Patch(collection_name string, selector interface{}, patch interface{}) error
Update(collection_name string, selector interface{}, update interface{}) error
UpdateAll(collection_name string, selector interface{}, update interface{}) (*ChangeResults, error)
DropDatabase() error
Expand Down
12 changes: 12 additions & 0 deletions common/database/mongo_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/HackIllinois/api/common/config"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)

/*
Expand Down Expand Up @@ -197,6 +198,17 @@ func (db *MongoDatabase) Upsert(collection_name string, selector interface{}, up
return &change_results, convertMgoError(err)
}

func (db *MongoDatabase) Patch(collection_name string, selector interface{}, patch interface{}) error {
current_session := db.GetSession()
defer current_session.Close()

collection := current_session.DB(db.name).C(collection_name)

err := collection.Update(selector, bson.M{"$set": patch})

return convertMgoError(err)
}

/*
Finds an item based on the given selector and updates it with the data in update
*/
Expand Down
35 changes: 29 additions & 6 deletions common/datastore/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,28 @@ package datastore

import (
"fmt"

"gopkg.in/go-playground/validator.v9"
)

func (datastore *DataStore) Validate() error {
validate := validator.New()

return validateField(datastore.Data, datastore.Definition, validate)
return validateField(datastore.Data, datastore.Definition, validate, false)
}

func (datastore *DataStore) ValidateNonEmpty() error {
validate := validator.New()

return validateField(datastore.Data, datastore.Definition, validate, true)
}

func validateField(data interface{}, definition DataStoreDefinition, validate *validator.Validate) error {
func validateField(
data interface{},
definition DataStoreDefinition,
validate *validator.Validate,
ignore_empty bool,
) error {
err := validate.Var(data, definition.Validations)

if err != nil {
Expand All @@ -26,7 +38,7 @@ func validateField(data interface{}, definition DataStoreDefinition, validate *v
return NewErrTypeMismatch(data, "map[string]interface{}")
}

return validateFieldArray(mapped_data, definition, validate)
return validateFieldArray(mapped_data, definition, validate, ignore_empty)
case "[]object":
data_array, ok := data.([]map[string]interface{})

Expand All @@ -35,7 +47,7 @@ func validateField(data interface{}, definition DataStoreDefinition, validate *v
}

for _, mapped_data := range data_array {
err = validateFieldArray(mapped_data, definition, validate)
err = validateFieldArray(mapped_data, definition, validate, ignore_empty)

if err != nil {
return err
Expand All @@ -48,9 +60,20 @@ func validateField(data interface{}, definition DataStoreDefinition, validate *v
}
}

func validateFieldArray(data map[string]interface{}, definition DataStoreDefinition, validate *validator.Validate) error {
func validateFieldArray(
data map[string]interface{},
definition DataStoreDefinition,
validate *validator.Validate,
ignore_empty bool,
) error {
for _, field := range definition.Fields {
err := validateField(data[field.Name], field, validate)
if ignore_empty {
if _, ok := data[field.Name]; !ok {
continue
}
}

err := validateField(data[field.Name], field, validate, ignore_empty)

if err != nil {
return err
Expand Down
10 changes: 10 additions & 0 deletions gateway/services/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ var RegistrationRoutes = arbor.RouteCollection{
"/registration/attendee/",
alice.New(middleware.AuthMiddleware([]models.Role{models.ApplicantRole}), middleware.IdentificationMiddleware).ThenFunc(UpdateRegistration).ServeHTTP,
},
arbor.Route{
"PatchCurrentUserRegistration",
"PATCH",
"/registration/attendee/",
alice.New(middleware.AuthMiddleware([]models.Role{models.ApplicantRole}), middleware.IdentificationMiddleware).ThenFunc(PatchRegistration).ServeHTTP,
},
arbor.Route{
"GetFilteredUserRegistrations",
"GET",
Expand Down Expand Up @@ -97,3 +103,7 @@ func CreateRegistration(w http.ResponseWriter, r *http.Request) {
func UpdateRegistration(w http.ResponseWriter, r *http.Request) {
arbor.PUT(w, config.REGISTRATION_SERVICE+r.URL.String(), RegistrationFormat, "", r)
}

func PatchRegistration(w http.ResponseWriter, r *http.Request) {
arbor.PATCH(w, config.REGISTRATION_SERVICE+r.URL.String(), RegistrationFormat, "", r)
}
58 changes: 58 additions & 0 deletions services/registration/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func SetupController(route *mux.Route) {
router.HandleFunc("/attendee/", GetCurrentUserRegistration).Methods("GET")
router.HandleFunc("/attendee/", CreateCurrentUserRegistration).Methods("POST")
router.HandleFunc("/attendee/", UpdateCurrentUserRegistration).Methods("PUT")
router.HandleFunc("/attendee/", PatchCurrentUserRegistration).Methods("PATCH")
router.HandleFunc("/attendee/filter/", GetFilteredUserRegistrations).Methods("GET")

router.HandleFunc("/mentor/", GetCurrentMentorRegistration).Methods("GET")
Expand Down Expand Up @@ -257,6 +258,63 @@ func UpdateCurrentUserRegistration(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(updated_registration)
}

/*
Endpoint to patch user registration attributes
*/
func PatchCurrentUserRegistration(w http.ResponseWriter, r *http.Request) {
id := r.Header.Get("HackIllinois-Identity")

if id == "" {
errors.WriteError(w, r, errors.MalformedRequestError("Must provide id in request.", "Must provide id in request."))
return
}

var patch_data map[string]interface{}
err := json.NewDecoder(r.Body).Decode(&patch_data)

if err != nil {
errors.WriteError(w, r, errors.InternalError(err.Error(), "Could not decode user registration information. Possible failure in JSON validation, or invalid registration format."))
return
}

patch_data["id"] = id

registration_patch := datastore.NewDataStore(config.REGISTRATION_DEFINITION)
for _, field := range registration_patch.Definition.Fields {
if _, ok := patch_data[field.Name]; !ok {
delete(patch_data, field.Name)
}
}

registration_patch.Data = patch_data;

registration_patch.Data["updatedAt"] = time.Now().Unix()

err = service.PatchUserRegistration(id, registration_patch)

if err != nil {
errors.WriteError(w, r, errors.InternalError(err.Error(), "Could not update user's registration."))
return
}

updated_registration, err := service.GetUserRegistration(id)

if err != nil {
errors.WriteError(w, r, errors.DatabaseError(err.Error(), "Could not fetch user's updated registration."))
return
}

mail_template := "registration_update"
err = service.SendUserMail(id, mail_template)

if err != nil {
errors.WriteError(w, r, errors.InternalError(err.Error(), "Could not send registration update email."))
return
}

json.NewEncoder(w).Encode(updated_registration)
}

/*
Endpoint to get user registrations based on filters
*/
Expand Down
22 changes: 20 additions & 2 deletions services/registration/service/registration_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ package service

import (
"errors"
"strconv"
"strings"

"github.com/HackIllinois/api/common/database"
"github.com/HackIllinois/api/services/registration/config"
"github.com/HackIllinois/api/services/registration/models"
"gopkg.in/go-playground/validator.v9"
"strconv"
"strings"
)

var validate *validator.Validate
Expand Down Expand Up @@ -89,6 +90,23 @@ func UpdateUserRegistration(id string, user_registration models.UserRegistration
return err
}

/*
Patches the user registration associated with the given user id
*/
func PatchUserRegistration(id string, registration_patch models.UserRegistration) error {
err := registration_patch.ValidateNonEmpty()

if err != nil {
return err
}

selector := database.QuerySelector{"id": id}

err = db.Patch("attendees", selector, &registration_patch)

return err
}

/*
Returns db search query based on given parameters
*/
Expand Down
47 changes: 47 additions & 0 deletions services/registration/tests/registration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,44 @@ func TestUpdateUserRegistrationService(t *testing.T) {
CleanupTestDB(t)
}

/*
Service level test for patching user registration in the db
*/
func TestPatchUserRegistrationService(t *testing.T) {
SetupTestDB(t)
test_registration := datastore.NewDataStore(config.REGISTRATION_DEFINITION)
json.Unmarshal([]byte(patch_registration_data), &test_registration)
test_data := make (map[string]interface{})
test_data["firstName"] = "John"
test_data["lastName"] = "Smith"
test_data["email"] = "new_test@gmail.com"
test_registration.Data = test_data
fmt.Println(test_registration)
err := service.PatchUserRegistration("testid", test_registration)

if err != nil {
t.Fatal(err)
}

user_registration, err := service.GetUserRegistration("testid")

if err != nil {
t.Fatal(err)
}

expected_registration := getBaseUserRegistration()
expected_registration.Data["id"] = "testid"
expected_registration.Data["firstName"] = "John"
expected_registration.Data["lastName"] = "Smith"
expected_registration.Data["email"] = "new_test@gmail.com"

if !reflect.DeepEqual(user_registration.Data["firstName"], expected_registration.Data["firstName"]) {
t.Errorf("Wrong user info.\nExpected %v\ngot %v\n", expected_registration.Data["firstName"], user_registration.Data["firstName"])
}

CleanupTestDB(t)
}

/*
Service level test for getting mentor registration from db
*/
Expand Down Expand Up @@ -441,6 +479,15 @@ var user_registration_data string = `
}
`

var patch_registration_data string = `
{
"id": "testid",
"firstName": "John",
"lastName": "Smith",
"email": "new_test@gmail.com"
}
`

var mentor_registration_data string = `
{
"id": "testid",
Expand Down