func getUsers(p *passenger.Passenger, ctx context.Context, w http.ResponseWriter, r *http.Request) (status int, err error) { if p.UserKey.Parent() == nil { return http.StatusUnauthorized, nil } var invitations model.Invitations _, err = model.NewQueryForInvitation().Ancestor(p.UserKey.Parent()).GetAll(ctx, &invitations) if err != nil { return http.StatusInternalServerError, err } cckeys, err := model.NewQueryForChallenge().Ancestor(p.UserKey.Parent()).KeysOnly().GetAll(ctx, nil) if err != nil { return http.StatusInternalServerError, 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...) } var users model.Users keys, err := model.NewQueryForUser().GetAll(ctx, &users) if err != nil { return http.StatusInternalServerError, err } finishedUsers := make([]*datastore.Key, len(resultKeys)) for i := range resultKeys { finishedUsers[i] = resultKeys[i].Parent().Parent() } // 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 } mappedStates := make(map[string]string) for _, val := range invitedUsers { mappedStates[val.Encode()] = "invited" } for _, val := range finishedUsers { mappedStates[val.Encode()] = "coding" } 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()], } } json.NewEncoder(w).Encode(usersWithState) return http.StatusOK, nil }
// FromBasicAuth tries do identify a Passenger by the access token he gave us. // It will look up the the user by username and try to match password. func FromBasicAuth(ctx context.Context, username, pw string) (p *Passenger, err error) { p = new(Passenger) var user model.User p.UserKey, err = model.NewQueryForUser(). Filter("Nick=", username). Limit(1). Run(ctx). Next(&user) if err != nil { return } err = password.Check([]byte(pw), user.HashedPassword) // TODO(flowlo): Depending on bcrypt is very fragile. We // should encapsulate that. if err == bcrypt.ErrMismatchedHashAndPassword { userKey := p.UserKey p, err = FromAccessToken(ctx, pw) if err != nil { return } if !p.UserKey.Equal(userKey) { return nil, ErrTokenNotMatchingUser{Parent: p.UserKey, Actual: userKey} } } return }
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) if err != nil { return false, err } return len(k) == 1, nil }
// GetUsersByCompany queries the user accounts belonging to a company. func GetUsersByCompany(ctx context.Context, w http.ResponseWriter, r *http.Request) (int, error) { if !util.CheckMethod(r, "GET") { return http.StatusMethodNotAllowed, nil } key, err := datastore.DecodeKey(r.URL.Query()["result"][0]) if err != nil { return http.StatusBadRequest, err } var users model.Users keys, err := model.NewQueryForUser(). Ancestor(key). GetAll(ctx, &users) if err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(users.Key(keys)) return http.StatusOK, nil }
// 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" { return http.StatusMethodNotAllowed, nil } if err := initInvitationTemplate(); err != nil { return http.StatusInternalServerError, err } p, ok := passenger.FromContext(ctx) if !ok { return http.StatusUnauthorized, nil } var u model.User if err = datastore.Get(ctx, p.User, &u); err != nil { return http.StatusInternalServerError, nil } cKey := u.Company if cKey == nil { return http.StatusUnauthorized, nil } var company model.Company if err = datastore.Get(ctx, cKey, &company); err != nil { return http.StatusInternalServerError, err } var params = struct { Address, Challenge string }{} if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { return http.StatusBadRequest, err } address, err := mail.ParseAddress(params.Address) if err != nil { return http.StatusBadRequest, err } challengeKey, err := datastore.DecodeKey(params.Challenge) if err != nil { return http.StatusBadRequest, err } var challenge model.Challenge if err := datastore.Get(ctx, challengeKey, &challenge); err != nil { // TODO(flowlo): Actually look into err. If it is just something like // "not found", an internal server error is not appropriate. return http.StatusInternalServerError, err } // TODO(flowlo): Check whether the parent of the current user is the // parent of the challenge (if any), and check whether the challenge // even exists. var users model.Users keys, err := model.NewQueryForUser(). Filter("Address=", address.Address). Limit(1). GetAll(ctx, &users) if err != nil { return http.StatusInternalServerError, err } var key *datastore.Key var user model.User if len(keys) == 1 { key = keys[0] user = users[0] } else { user = model.User{Address: *address} key, err = user.Put(ctx, nil) if err != nil { return http.StatusInternalServerError, err } profile := model.Profile{} if _, err = profile.PutWithParent(ctx, key); err != nil { return http.StatusInternalServerError, err } } // NOTE: We are creating a new, orphaned Passenger here, because a // Passenger can only issue tokens for the encapsulated user. np := passenger.Passenger{ User: key, } now := time.Now() token := &model.Token{ Creation: now, Expiry: now.Add(time.Hour * 24 * 365), Description: "Initialization Token", } value, err := np.IssueToken(ctx, token) if err != nil { return http.StatusInternalServerError, err } query := base64.URLEncoding.EncodeToString([]byte(params.Challenge + ":" + value)) i := model.Invitation{ User: key, } // If we're on dev, generate a URL that will point at the dev instance, not // production. // TODO(flowlo): Move this magic constant somewhere to be configured, as port // 6060 is no official thing. prefix := "https://app.cod.uno" if appengine.IsDevAppServer() { prefix = "http://*****:*****@cod.uno>", To: []string{user.Address.String()}, Subject: "We challenge you!", Body: buf.String(), }); err != nil { return http.StatusInternalServerError, err } key, err = i.PutWithParent(ctx, cKey) if err != nil { return http.StatusInternalServerError, err } json.NewEncoder(w).Encode(i.Key(key)) return http.StatusOK, nil }