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
16 changes: 16 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 All @@ -60,6 +66,12 @@ var RegistrationRoutes = arbor.RouteCollection{
"/registration/mentor/",
alice.New(middleware.AuthMiddleware([]models.Role{models.MentorRole}), middleware.IdentificationMiddleware).ThenFunc(UpdateRegistration).ServeHTTP,
},
arbor.Route{
"PatchCurrentMentorRegistration",
"PATCH",
"/registration/mentor/",
alice.New(middleware.AuthMiddleware([]models.Role{models.UserRole}), middleware.IdentificationMiddleware).ThenFunc(PatchRegistration).ServeHTTP,
},
arbor.Route{
"GetFilteredMentorRegistrations",
"GET",
Expand Down Expand Up @@ -97,3 +109,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)
}
116 changes: 116 additions & 0 deletions services/registration/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ 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")
router.HandleFunc("/mentor/", CreateCurrentMentorRegistration).Methods("POST")
router.HandleFunc("/mentor/", UpdateCurrentMentorRegistration).Methods("PUT")
router.HandleFunc("/mentor/", PatchCurrentMentorRegistration).Methods("PATCH")
router.HandleFunc("/mentor/filter/", GetFilteredMentorRegistrations).Methods("GET")

router.HandleFunc("/{id}/", GetAllRegistrations).Methods("GET")
Expand Down Expand Up @@ -257,6 +259,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 Expand Up @@ -402,6 +461,63 @@ func UpdateCurrentMentorRegistration(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(updated_registration)
}

/*
Endpoint to patch mentor registration attributes
*/
func PatchCurrentMentorRegistration(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 mentor registration information. Possible failure in JSON validation, or invalid registration format."))
return
}

patch_data["id"] = id

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

mentor_registration_patch.Data = patch_data;

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

err = service.PatchMentorRegistration(id, mentor_registration_patch)

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

updated_registration, err := service.GetMentorRegistration(id)

if err != nil {
errors.WriteError(w, r, errors.DatabaseError(err.Error(), "Could not fetch mentor'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 mentor registrations based on filters
*/
Expand Down
39 changes: 37 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 Expand Up @@ -214,6 +232,23 @@ func UpdateMentorRegistration(id string, mentor_registration models.MentorRegist
return err
}

/*
Patches the mentor registration associated with the given user id
*/
func PatchMentorRegistration(id string, mentor_registration_patch models.MentorRegistration) error {
err := mentor_registration_patch.ValidateNonEmpty()

if err != nil {
return err
}

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

err = db.Patch("mentors", selector, &mentor_registration_patch)

return err
}

/*
Returns the mentor registrations associated with the given parameters
*/
Expand Down
Loading