diff --git a/controllers/invitation.go b/controllers/invitation.go index 5adbe8a..3420c46 100644 --- a/controllers/invitation.go +++ b/controllers/invitation.go @@ -37,10 +37,16 @@ func initInvitationTemplate() error { // Invitation handles the creation of a new invitation and sends an e-mail to // the user. func Invitation(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { - if r.Method != "POST" { + switch r.Method { + case "POST": + return createInvitation(ctx, w, r) + case "GET": + return GetUsersInvitedByCompany(ctx, w, r) + default: return http.StatusMethodNotAllowed, nil } - +} +func createInvitation(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { if err := initInvitationTemplate(); err != nil { return http.StatusInternalServerError, err } diff --git a/controllers/user.go b/controllers/user.go index 765ee74..29bffce 100644 --- a/controllers/user.go +++ b/controllers/user.go @@ -4,6 +4,7 @@ import ( "errors" "net/http" "net/mail" + "time" "encoding/json" @@ -18,7 +19,7 @@ import ( type keyedUserWithState struct { *model.KeyedUser - State string + States []string } func init() { @@ -153,75 +154,120 @@ func getUsers(p *passenger.Passenger, ctx context.Context, w http.ResponseWriter if u.Company == nil { return http.StatusUnauthorized, nil } - var invitations model.Invitations - _, err = model.NewQueryForInvitation().Ancestor(u.Company).GetAll(ctx, &invitations) + var users model.Users + keys, err := model.NewQueryForUser().GetAll(ctx, &users) if err != nil { return http.StatusInternalServerError, err } + json.NewEncoder(w).Encode(users.Key(keys)) + return http.StatusOK, nil +} + +func alreadyExists(ctx context.Context, property, value string) (exists bool, err error) { + k, err := model.NewQueryForUser(). + KeysOnly(). + Limit(1). + Filter(property+"=", value). + GetAll(ctx, nil) - cckeys, err := model.NewQueryForChallenge().Ancestor(u.Company).KeysOnly().GetAll(ctx, nil) if err != nil { - return http.StatusInternalServerError, err + return false, err } - var resultKeys []*datastore.Key - for _, val := range cckeys { - rkeys, err := model.NewQueryForResult().Filter("Challenge =", val).KeysOnly().GetAll(ctx, nil) - if err != nil { - return http.StatusInternalServerError, err - } - resultKeys = append(resultKeys, rkeys...) - } + return len(k) == 1, nil +} - var users model.Users - keys, err := model.NewQueryForUser().GetAll(ctx, &users) - if err != nil { - return http.StatusInternalServerError, err +func GetUsersInvitedByCompany(ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { + if r.Method != "GET" { + return http.StatusMethodNotAllowed, nil } - - finishedUsers := make([]*datastore.Key, len(resultKeys)) - for i := range resultKeys { - finishedUsers[i] = resultKeys[i].Parent().Parent() + p, ok := passenger.FromContext(ctx) + if !ok { + return http.StatusUnauthorized, nil } - - // TODO(victorbalan): Don`t load invited users that have an result. - invitedUsers := make([]*datastore.Key, len(invitations)) - for i, val := range invitations { - invitedUsers[i] = val.User + var u model.User + if err = datastore.Get(ctx, p.User, &u); err != nil { + return http.StatusInternalServerError, nil } - mappedStates := make(map[string]string) - for _, val := range invitedUsers { - mappedStates[val.Encode()] = "invited" + + if u.Company == nil { + return http.StatusUnauthorized, nil } - for _, val := range finishedUsers { - mappedStates[val.Encode()] = "coding" + + var invitations model.Invitations + _, err = model.NewQueryForInvitation().Ancestor(u.Company).GetAll(ctx, &invitations) + m := make(map[string]int) + for _, inv := range invitations { + ek := inv.User.Encode() + if _, ok := m[ek]; !ok { + m[ek] = 1 + } else { + m[ek] = m[ek] + 1 + } } - usersWithState := make([]keyedUserWithState, len(users)) - for i := range users { - usersWithState[i] = keyedUserWithState{ - KeyedUser: &model.KeyedUser{ - User: &users[i], Key: keys[i], - }, - State: mappedStates[keys[i].Encode()], + var userList []*keyedUserWithState + var kUser *keyedUserWithState + for k, v := range m { + if kUser, err = getUserState(ctx, k, v); err != nil { + return http.StatusInternalServerError, err } + userList = append(userList, kUser) } - json.NewEncoder(w).Encode(usersWithState) + json.NewEncoder(w).Encode(userList) return http.StatusOK, nil } -func alreadyExists(ctx context.Context, property, value string) (exists bool, err error) { - k, err := model.NewQueryForUser(). - KeysOnly(). - Limit(1). - Filter(property+"=", value). - GetAll(ctx, nil) - +func getUserState(ctx context.Context, ek string, i int) (*keyedUserWithState, error) { + key, err := datastore.DecodeKey(ek) if err != nil { - return false, err + return nil, err + } + var user model.User + if err = datastore.Get(ctx, key, &user); err != nil { + return nil, err + } + var ( + profiles model.Profiles + keys []*datastore.Key + ) + if keys, err = model.NewQueryForProfile().Ancestor(key).GetAll(ctx, &profiles); err != nil { + return nil, err + } + + if len(keys) < 1 { + return nil, errors.New("Profile not found") + } + + kUser := &keyedUserWithState{ + user.Key(key), + make([]string, 0), + } + var results model.Results + if _, err := model.NewQueryForResult(). + Ancestor(keys[0]). + Order("Started"). + GetAll(ctx, &results); err != nil { + return nil, err + } + if len(results) < i { + // User was invited but has not yet started at least one of the + // challenges that he was invited at. + kUser.States = append(kUser.States, "invited") + } + finished := true + for _, result := range results { + if result.Started.Before(time.Now()) && result.Finished.IsZero() { + kUser.States = append(kUser.States, "coding") + finished = false + break + } + } + if len(results) == i && finished { + kUser.States = append(kUser.States, "finished") } - return len(k) == 1, nil + return kUser, nil } // GetUsersByCompany queries the user accounts belonging to a company.