Skip to content
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
10 changes: 8 additions & 2 deletions controllers/invitation.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
142 changes: 94 additions & 48 deletions controllers/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"net/http"
"net/mail"
"time"

"encoding/json"

Expand All @@ -18,7 +19,7 @@ import (

type keyedUserWithState struct {
*model.KeyedUser
State string
States []string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should have a type State string with a few consts. Is it possible for a user to be in multiple states? If yes, does it make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure it makes sense. He could be invited to 2 challenges. Or he could be invited to one and coding another.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed.

}

func init() {
Expand Down Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you really want to declare four variables here use:

var (
    x int
    y complex128
)

Keep in mind that variables should be declared as close to their first use as possible.

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.
Expand Down