1// Copyright (C) 2019 Storj Labs, Inc. 2// See LICENSE for copying information. 3 4package consoleql 5 6import ( 7 "github.com/graphql-go/graphql" 8 "go.uber.org/zap" 9 10 "storj.io/common/uuid" 11 "storj.io/storj/private/post" 12 "storj.io/storj/satellite/console" 13 "storj.io/storj/satellite/mailservice" 14) 15 16const ( 17 // Mutation is graphql request that modifies data. 18 Mutation = "mutation" 19 20 // CreateProjectMutation is a mutation name for project creation. 21 CreateProjectMutation = "createProject" 22 // DeleteProjectMutation is a mutation name for project deletion. 23 DeleteProjectMutation = "deleteProject" 24 // UpdateProjectMutation is a mutation name for project name and description updating. 25 UpdateProjectMutation = "updateProject" 26 27 // AddProjectMembersMutation is a mutation name for adding new project members. 28 AddProjectMembersMutation = "addProjectMembers" 29 // DeleteProjectMembersMutation is a mutation name for deleting project members. 30 DeleteProjectMembersMutation = "deleteProjectMembers" 31 32 // CreateAPIKeyMutation is a mutation name for api key creation. 33 CreateAPIKeyMutation = "createAPIKey" 34 // DeleteAPIKeysMutation is a mutation name for api key deleting. 35 DeleteAPIKeysMutation = "deleteAPIKeys" 36 37 // AddPaymentMethodMutation is mutation name for adding new payment method. 38 AddPaymentMethodMutation = "addPaymentMethod" 39 // DeletePaymentMethodMutation is mutation name for deleting payment method. 40 DeletePaymentMethodMutation = "deletePaymentMethod" 41 // SetDefaultPaymentMethodMutation is mutation name setting payment method as default payment method. 42 SetDefaultPaymentMethodMutation = "setDefaultPaymentMethod" 43 44 // InputArg is argument name for all input types. 45 InputArg = "input" 46 // ProjectFields is a field name for project specific fields. 47 ProjectFields = "projectFields" 48 // ProjectLimits is a field name for project specific limits. 49 ProjectLimits = "projectLimits" 50 // FieldProjectID is field name for projectID. 51 FieldProjectID = "projectID" 52 // FieldNewPassword is a field name for new password. 53 FieldNewPassword = "newPassword" 54 // Secret is a field name for registration token for user creation during Vanguard release. 55 Secret = "secret" 56 // ReferrerUserID is a field name for passing referrer's user id. 57 ReferrerUserID = "referrerUserId" 58) 59 60// rootMutation creates mutation for graphql populated by AccountsClient. 61func rootMutation(log *zap.Logger, service *console.Service, mailService *mailservice.Service, types *TypeCreator) *graphql.Object { 62 return graphql.NewObject(graphql.ObjectConfig{ 63 Name: Mutation, 64 Fields: graphql.Fields{ 65 // creates project from input params 66 CreateProjectMutation: &graphql.Field{ 67 Type: types.project, 68 Args: graphql.FieldConfigArgument{ 69 InputArg: &graphql.ArgumentConfig{ 70 Type: graphql.NewNonNull(types.projectInput), 71 }, 72 }, 73 Resolve: func(p graphql.ResolveParams) (interface{}, error) { 74 var projectInput = fromMapProjectInfo(p.Args[InputArg].(map[string]interface{})) 75 76 project, err := service.CreateProject(p.Context, projectInput) 77 if err != nil { 78 return nil, err 79 } 80 81 return project, nil 82 }, 83 }, 84 // deletes project by id, taken from input params 85 DeleteProjectMutation: &graphql.Field{ 86 Type: types.project, 87 Args: graphql.FieldConfigArgument{ 88 FieldID: &graphql.ArgumentConfig{ 89 Type: graphql.NewNonNull(graphql.String), 90 }, 91 }, 92 Resolve: func(p graphql.ResolveParams) (interface{}, error) { 93 return nil, console.ErrUnauthorized.New("not implemented") 94 }, 95 }, 96 // updates project name and description. 97 UpdateProjectMutation: &graphql.Field{ 98 Type: types.project, 99 Args: graphql.FieldConfigArgument{ 100 FieldID: &graphql.ArgumentConfig{ 101 Type: graphql.NewNonNull(graphql.String), 102 }, 103 ProjectFields: &graphql.ArgumentConfig{ 104 Type: graphql.NewNonNull(types.projectInput), 105 }, 106 ProjectLimits: &graphql.ArgumentConfig{ 107 Type: graphql.NewNonNull(types.projectLimit), 108 }, 109 }, 110 Resolve: func(p graphql.ResolveParams) (interface{}, error) { 111 var projectInput, err = fromMapProjectInfoProjectLimits(p.Args[ProjectFields].(map[string]interface{}), p.Args[ProjectLimits].(map[string]interface{})) 112 if err != nil { 113 return nil, err 114 } 115 116 inputID := p.Args[FieldID].(string) 117 projectID, err := uuid.FromString(inputID) 118 if err != nil { 119 return nil, err 120 } 121 122 project, err := service.UpdateProject(p.Context, projectID, projectInput) 123 if err != nil { 124 return nil, err 125 } 126 127 return project, nil 128 }, 129 }, 130 // add user as member of given project 131 AddProjectMembersMutation: &graphql.Field{ 132 Type: types.project, 133 Args: graphql.FieldConfigArgument{ 134 FieldProjectID: &graphql.ArgumentConfig{ 135 Type: graphql.NewNonNull(graphql.String), 136 }, 137 FieldEmail: &graphql.ArgumentConfig{ 138 Type: graphql.NewNonNull(graphql.NewList(graphql.String)), 139 }, 140 }, 141 Resolve: func(p graphql.ResolveParams) (interface{}, error) { 142 pID, _ := p.Args[FieldProjectID].(string) 143 emails, _ := p.Args[FieldEmail].([]interface{}) 144 145 projectID, err := uuid.FromString(pID) 146 if err != nil { 147 return nil, err 148 } 149 150 var userEmails []string 151 for _, email := range emails { 152 userEmails = append(userEmails, email.(string)) 153 } 154 155 project, err := service.GetProject(p.Context, projectID) 156 if err != nil { 157 return nil, err 158 } 159 160 users, err := service.AddProjectMembers(p.Context, projectID, userEmails) 161 if err != nil { 162 return nil, err 163 } 164 165 rootObject := p.Info.RootValue.(map[string]interface{}) 166 origin := rootObject["origin"].(string) 167 signIn := origin + rootObject[SignInPath].(string) 168 169 for _, user := range users { 170 userName := user.ShortName 171 if user.ShortName == "" { 172 userName = user.FullName 173 } 174 175 contactInfoURL := rootObject[ContactInfoURL].(string) 176 letUsKnowURL := rootObject[LetUsKnowURL].(string) 177 termsAndConditionsURL := rootObject[TermsAndConditionsURL].(string) 178 179 mailService.SendRenderedAsync( 180 p.Context, 181 []post.Address{{Address: user.Email, Name: userName}}, 182 &ProjectInvitationEmail{ 183 Origin: origin, 184 UserName: userName, 185 ProjectName: project.Name, 186 SignInLink: signIn, 187 LetUsKnowURL: letUsKnowURL, 188 TermsAndConditionsURL: termsAndConditionsURL, 189 ContactInfoURL: contactInfoURL, 190 }, 191 ) 192 } 193 194 return project, nil 195 }, 196 }, 197 // delete user membership for given project 198 DeleteProjectMembersMutation: &graphql.Field{ 199 Type: types.project, 200 Args: graphql.FieldConfigArgument{ 201 FieldProjectID: &graphql.ArgumentConfig{ 202 Type: graphql.NewNonNull(graphql.String), 203 }, 204 FieldEmail: &graphql.ArgumentConfig{ 205 Type: graphql.NewNonNull(graphql.NewList(graphql.String)), 206 }, 207 }, 208 Resolve: func(p graphql.ResolveParams) (interface{}, error) { 209 pID, _ := p.Args[FieldProjectID].(string) 210 emails, _ := p.Args[FieldEmail].([]interface{}) 211 212 projectID, err := uuid.FromString(pID) 213 if err != nil { 214 return nil, err 215 } 216 217 var userEmails []string 218 for _, email := range emails { 219 userEmails = append(userEmails, email.(string)) 220 } 221 222 project, err := service.GetProject(p.Context, projectID) 223 if err != nil { 224 return nil, err 225 } 226 227 err = service.DeleteProjectMembers(p.Context, project.ID, userEmails) 228 if err != nil { 229 return nil, err 230 } 231 232 return project, nil 233 }, 234 }, 235 // creates new api key 236 CreateAPIKeyMutation: &graphql.Field{ 237 Type: types.createAPIKey, 238 Args: graphql.FieldConfigArgument{ 239 FieldProjectID: &graphql.ArgumentConfig{ 240 Type: graphql.NewNonNull(graphql.String), 241 }, 242 FieldName: &graphql.ArgumentConfig{ 243 Type: graphql.NewNonNull(graphql.String), 244 }, 245 }, 246 Resolve: func(p graphql.ResolveParams) (interface{}, error) { 247 projectIDField, _ := p.Args[FieldProjectID].(string) 248 name, _ := p.Args[FieldName].(string) 249 250 projectID, err := uuid.FromString(projectIDField) 251 if err != nil { 252 return nil, err 253 } 254 255 info, key, err := service.CreateAPIKey(p.Context, projectID, name) 256 if err != nil { 257 return nil, err 258 } 259 260 return createAPIKey{ 261 Key: key.Serialize(), 262 KeyInfo: info, 263 }, nil 264 }, 265 }, 266 // deletes api key 267 DeleteAPIKeysMutation: &graphql.Field{ 268 Type: graphql.NewList(types.apiKeyInfo), 269 Args: graphql.FieldConfigArgument{ 270 FieldID: &graphql.ArgumentConfig{ 271 Type: graphql.NewNonNull(graphql.NewList(graphql.String)), 272 }, 273 }, 274 Resolve: func(p graphql.ResolveParams) (interface{}, error) { 275 paramKeysID, _ := p.Args[FieldID].([]interface{}) 276 277 var keyIds []uuid.UUID 278 var keys []console.APIKeyInfo 279 for _, id := range paramKeysID { 280 keyID, err := uuid.FromString(id.(string)) 281 if err != nil { 282 return nil, err 283 } 284 285 key, err := service.GetAPIKeyInfo(p.Context, keyID) 286 if err != nil { 287 return nil, err 288 } 289 290 keyIds = append(keyIds, keyID) 291 keys = append(keys, *key) 292 } 293 294 err := service.DeleteAPIKeys(p.Context, keyIds) 295 if err != nil { 296 return nil, err 297 } 298 299 return keys, nil 300 }, 301 }, 302 AddPaymentMethodMutation: &graphql.Field{ 303 Type: graphql.Boolean, 304 Args: graphql.FieldConfigArgument{}, 305 Resolve: func(p graphql.ResolveParams) (interface{}, error) { 306 return nil, nil 307 }, 308 }, 309 DeletePaymentMethodMutation: &graphql.Field{ 310 Type: graphql.Boolean, 311 Args: graphql.FieldConfigArgument{}, 312 Resolve: func(p graphql.ResolveParams) (interface{}, error) { 313 return nil, nil 314 }, 315 }, 316 SetDefaultPaymentMethodMutation: &graphql.Field{ 317 Type: graphql.Boolean, 318 Args: graphql.FieldConfigArgument{}, 319 Resolve: func(p graphql.ResolveParams) (interface{}, error) { 320 return nil, nil 321 }, 322 }, 323 }, 324 }) 325} 326