1package service
2
3import (
4	"fmt"
5	"strings"
6
7	email_utils "github.com/keybase/client/go/emails"
8	"github.com/keybase/client/go/invitefriends"
9	"github.com/keybase/client/go/libkb"
10	keybase1 "github.com/keybase/client/go/protocol/keybase1"
11	"github.com/keybase/go-framed-msgpack-rpc/rpc"
12
13	"golang.org/x/net/context"
14)
15
16type InviteFriendsHandler struct {
17	libkb.Contextified
18	*BaseHandler
19}
20
21func NewInviteFriendsHandler(xp rpc.Transporter, g *libkb.GlobalContext) *InviteFriendsHandler {
22	handler := &InviteFriendsHandler{
23		Contextified: libkb.NewContextified(g),
24		BaseHandler:  NewBaseHandler(g, xp),
25	}
26	return handler
27}
28
29var _ keybase1.InviteFriendsInterface = (*InviteFriendsHandler)(nil)
30
31func (h *InviteFriendsHandler) InvitePeople(ctx context.Context, arg keybase1.InvitePeopleArg) (succeeded int, err error) {
32	mctx := libkb.NewMetaContext(ctx, h.G())
33	defer mctx.Trace("InviteFriendsHandler#InvitePeople", &err)()
34
35	if err := assertLoggedIn(ctx, h.G()); err != nil {
36		mctx.Debug("not logged in err: %v", err)
37		return 0, err
38	}
39
40	allOK := true
41	var assertions []string
42	if arg.Emails.EmailsFromContacts != nil {
43		for _, email := range *arg.Emails.EmailsFromContacts {
44			assertion, parseErr := libkb.ParseAssertionURLKeyValue(mctx.G().MakeAssertionContext(mctx), "email", email.String(), false)
45			if parseErr != nil {
46				allOK = false
47				mctx.Debug("failed to parse email %q; skipping: %s", email, parseErr)
48				continue
49			}
50			assertions = append(assertions, assertion.String())
51		}
52	}
53	if arg.Emails.CommaSeparatedEmailsFromUser != nil {
54		var malformed []string
55		parsedEmails := email_utils.ParseSeparatedEmails(mctx, *arg.Emails.CommaSeparatedEmailsFromUser, &malformed)
56		if len(malformed) > 0 {
57			allOK = false
58		}
59
60		actx := mctx.G().MakeAssertionContext(mctx)
61		for _, email := range parsedEmails {
62			// `strict` argument here doesn't actually do anything for "email" assertions.
63			assertion, parseErr := libkb.ParseAssertionURLKeyValue(actx, "email", email, false /* strict */)
64			if parseErr != nil {
65				mctx.Debug("failed to create assertion from email %q: %s", email, parseErr)
66				allOK = false
67				continue
68			}
69			assertions = append(assertions, assertion.String())
70		}
71	}
72	for _, phone := range arg.Phones {
73		phoneStr := strings.TrimPrefix(phone.String(), "+")
74		assertion, parseErr := libkb.ParseAssertionURLKeyValue(mctx.G().MakeAssertionContext(mctx), "phone", phoneStr, false)
75		if parseErr != nil {
76			allOK = false
77			mctx.Debug("failed to parse phone number %q; skipping: %s", phone, parseErr)
78			continue
79		}
80		assertions = append(assertions, assertion.String())
81	}
82
83	if len(assertions) == 0 {
84		if allOK {
85			return 0, nil
86		}
87		return 0, fmt.Errorf("failed to parse any email or phone number")
88	}
89
90	type apiRes struct {
91		libkb.AppStatusEmbed
92	}
93	payload := make(libkb.JSONPayload)
94	payload["assertions"] = assertions
95	apiArg := libkb.APIArg{
96		Endpoint:    "invite_friends/invite",
97		SessionType: libkb.APISessionTypeREQUIRED,
98		JSONPayload: payload,
99	}
100	var res apiRes
101	err = mctx.G().API.PostDecode(mctx, apiArg, &res)
102	if err != nil {
103		return 0, err
104	}
105	return len(assertions), nil
106}
107
108func (h *InviteFriendsHandler) GetInviteCounts(ctx context.Context) (counts keybase1.InviteCounts, err error) {
109	mctx := libkb.NewMetaContext(ctx, h.G())
110	defer mctx.Trace("InviteFriendsHandler#GetInviteCounts", &err)()
111
112	return invitefriends.GetCounts(mctx)
113}
114
115func (h *InviteFriendsHandler) RequestInviteCounts(ctx context.Context) (err error) {
116	mctx := libkb.NewMetaContext(ctx, h.G())
117	defer mctx.Trace("InviteFriendsHandler#RequestInviteCounts", &err)()
118
119	return invitefriends.RequestNotification(mctx)
120}
121