Example #1
0
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
}
Example #2
0
// 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
}
Example #3
0
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
}
Example #4
0
// 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
}
Example #5
0
// 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(&params); 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://localhost:6060"
	}

	buf := new(bytes.Buffer)
	if err = invitation.Execute(buf, struct {
		UserAddress, CompanyAddress mail.Address
		URL                         string
	}{
		user.Address,
		company.Address,
		prefix + "/#!/token/" + query,
	}); err != nil {
		return http.StatusInternalServerError, err
	}

	if err = appmail.Send(ctx, &appmail.Message{
		Sender:  "Lorenz Leutgeb <[email protected]>",
		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
}