@@ -10,6 +10,7 @@ import (
1010
1111 v2 "github.com/conductorone/baton-sdk/pb/c1/connector/v2"
1212 "github.com/conductorone/baton-sdk/pkg/annotations"
13+ "github.com/conductorone/baton-sdk/pkg/connectorbuilder"
1314 "github.com/conductorone/baton-sdk/pkg/pagination"
1415 "github.com/conductorone/baton-sdk/pkg/types/resource"
1516 "github.com/google/go-github/v69/github"
@@ -19,6 +20,32 @@ import (
1920 "google.golang.org/protobuf/types/known/timestamppb"
2021)
2122
23+ func invitationToUserResource (invitation * github.Invitation ) (* v2.Resource , error ) {
24+ login := invitation .GetLogin ()
25+ if login == "" {
26+ login = invitation .GetEmail ()
27+ }
28+
29+ ret , err := resource .NewUserResource (
30+ login ,
31+ resourceTypeUser ,
32+ invitation .GetID (),
33+ []resource.UserTraitOption {
34+ resource .WithEmail (invitation .GetEmail (), true ),
35+ resource .WithUserProfile (map [string ]interface {}{
36+ "login" : login ,
37+ "inviter" : invitation .GetInviter ().GetLogin (),
38+ }),
39+ resource .WithStatus (v2 .UserTrait_Status_STATUS_UNSPECIFIED ),
40+ resource .WithUserLogin (login ),
41+ },
42+ )
43+ if err != nil {
44+ return nil , err
45+ }
46+ return ret , nil
47+ }
48+
2249// Create a new connector resource for a GitHub user.
2350func userResource (ctx context.Context , user * github.User , userEmail string , extraEmails []string ) (* v2.Resource , error ) {
2451 displayName := user .GetName ()
@@ -211,6 +238,107 @@ func (o *userResourceType) List(ctx context.Context, parentID *v2.ResourceId, pt
211238 return rv , pageToken , annotations , nil
212239}
213240
241+ func (o * userResourceType ) CreateAccountCapabilityDetails (ctx context.Context ) (* v2.CredentialDetailsAccountProvisioning , annotations.Annotations , error ) {
242+ return & v2.CredentialDetailsAccountProvisioning {
243+ SupportedCredentialOptions : []v2.CapabilityDetailCredentialOption {
244+ v2 .CapabilityDetailCredentialOption_CAPABILITY_DETAIL_CREDENTIAL_OPTION_NO_PASSWORD ,
245+ },
246+ PreferredCredentialOption : v2 .CapabilityDetailCredentialOption_CAPABILITY_DETAIL_CREDENTIAL_OPTION_NO_PASSWORD ,
247+ }, nil , nil
248+ }
249+
250+ func (o * userResourceType ) CreateAccount (
251+ ctx context.Context ,
252+ accountInfo * v2.AccountInfo ,
253+ credentialOptions * v2.CredentialOptions ,
254+ ) (
255+ connectorbuilder.CreateAccountResponse ,
256+ []* v2.PlaintextData ,
257+ annotations.Annotations ,
258+ error ,
259+ ) {
260+ params , err := getCreateUserParams (accountInfo )
261+ if err != nil {
262+ return nil , nil , nil , fmt .Errorf ("github-connectorv2: failed to get CreateUserParams: %w" , err )
263+ }
264+
265+ invitation , resp , err := o .client .Organizations .CreateOrgInvitation (ctx , params .org , & github.CreateOrgInvitationOptions {
266+ InviteeID : params .userID ,
267+ Role : params .role ,
268+ Email : params .email ,
269+ })
270+ if err != nil {
271+ return nil , nil , nil , fmt .Errorf ("github-connectorv2: failed to invite user to org: %w" , err )
272+ }
273+
274+ restApiRateLimit , err := extractRateLimitData (resp )
275+ if err != nil {
276+ return nil , nil , nil , err
277+ }
278+
279+ var annotations annotations.Annotations
280+ annotations .WithRateLimiting (restApiRateLimit )
281+
282+ r , err := invitationToUserResource (invitation )
283+ if err != nil {
284+ return nil , nil , nil , fmt .Errorf ("github-connectorv2: cannot create user resource: %w" , err )
285+ }
286+ return & v2.CreateAccountResponse_SuccessResult {
287+ Resource : r ,
288+ }, nil , nil , nil
289+ }
290+
291+ type createUserParams struct {
292+ org string
293+ email * string
294+ userID * int64
295+ role * string
296+ }
297+
298+ func getCreateUserParams (accountInfo * v2.AccountInfo ) (* createUserParams , error ) {
299+ var (
300+ pMap = accountInfo .Profile .AsMap ()
301+ uID * int64
302+ role * string
303+ email * string
304+ )
305+
306+ org , ok := pMap ["org" ].(string )
307+ if ! ok || org == "" {
308+ return nil , fmt .Errorf ("org is required" )
309+ }
310+
311+ e , emailExisted := pMap ["email" ].(string )
312+ if e != "" {
313+ email = & e
314+ }
315+
316+ userID , userIDExisted := pMap ["userID" ].(string )
317+ if ! emailExisted && ! userIDExisted {
318+ return nil , fmt .Errorf ("either email or userID should be provided" )
319+ }
320+
321+ if userIDExisted {
322+ i , err := strconv .ParseInt (userID , 10 , 64 )
323+ if err != nil {
324+ return nil , err
325+ }
326+ uID = & i
327+ }
328+
329+ r , _ := pMap ["role" ].(string )
330+ if r != "" {
331+ role = & r
332+ }
333+
334+ return & createUserParams {
335+ org : org ,
336+ email : email ,
337+ userID : uID ,
338+ role : role ,
339+ }, nil
340+ }
341+
214342func isEmail (email string ) bool {
215343 _ , err := mail .ParseAddress (email )
216344 return err == nil
0 commit comments