├── .gitignore
├── .graphqlconfig.yml
├── README.md
├── amplify
├── .config
│ └── project-config.json
└── backend
│ ├── api
│ └── gqls3test
│ │ ├── parameters.json
│ │ ├── schema.graphql
│ │ └── stacks
│ │ └── CustomResources.json
│ ├── auth
│ └── gqls3testeb3f615e
│ │ ├── gqls3testeb3f615e-cloudformation-template.yml
│ │ └── parameters.json
│ ├── backend-config.json
│ └── storage
│ └── gqls3test
│ ├── parameters.json
│ └── s3-cloudformation-template.json
├── package.json
├── public
├── favicon.ico
├── index.html
└── manifest.json
├── src
├── App.css
├── App.js
├── App.test.js
├── graphql
│ ├── mutations.js
│ ├── queries.js
│ ├── schema.json
│ └── subscriptions.js
├── index.css
├── index.js
├── logo.svg
└── serviceWorker.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | #amplify
26 | amplify/team-provider-info.json
27 | amplify/\#current-cloud-backend
28 | amplify/.config/local-*
29 | amplify/backend/amplify-meta.json
30 | amplify/backend/awscloudformation
31 | build/
32 | dist/
33 | node_modules/
34 | aws-exports.js
35 | awsconfiguration.json
--------------------------------------------------------------------------------
/.graphqlconfig.yml:
--------------------------------------------------------------------------------
1 | projects:
2 | gqls3test:
3 | schemaPath: src/graphql/schema.json
4 | includes:
5 | - src/graphql/**/*.js
6 | excludes:
7 | - ./amplify/**
8 | extensions:
9 | amplify:
10 | codeGenTarget: javascript
11 | generatedFileName: ''
12 | docsFilePath: src/graphql
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Image uploads and downloads with React, AWS Amplify, AWS AppSync, and Amazon S3
2 |
3 | This is an example project showing how to upload and download images from S3 using AWS Amplify, AWS AppSync, and Amazon S3
4 |
5 | ### The question
6 |
7 | How do I securely upload images using GraphQL with AWS AppSync?
8 |
9 | ### The solution
10 |
11 | There are a few parts to this solution:
12 |
13 | * You must first upload the image to a storage solution (Amazon S3)
14 | * After you have finished uploading the image, you will then be given a `key` to reference this image. You then need to store this reference in a database using a GraphQL mutation.
15 | * When you want to view this image, you need to do two things:
16 | * First, query the image reference from your database using GraphQL
17 | * Get a signed URL for the image from S3
18 |
19 | In this example, I show how to:
20 |
21 | 1. Store images using GraphQL, AppSync, and S3
22 | 2. Fetch a list of images and render them in a React application
23 |
24 | > To view the main code for this app, open [src/App.js](https://github.com/dabit3/react-amplify-appsync-s3/blob/master/src/App.js)
25 |
26 | ## To deploy this app
27 |
28 | 1. Clone the project and change into the directory
29 |
30 | ```sh
31 | git clone https://github.com/dabit3/react-amplify-appsync-s3.git
32 |
33 | cd react-amplify-appsync-s3
34 | ```
35 |
36 | 2. Install the dependencies
37 |
38 | ```sh
39 | npm install
40 |
41 | # or
42 |
43 | yarn
44 | ```
45 |
46 | 3. Initialize and deploy the amplify project
47 |
48 | ```sh
49 | amplify init
50 |
51 | amplify push
52 | ```
53 |
54 | 4. Run the app
55 |
56 | ```sh
57 | npm start
58 | ```
--------------------------------------------------------------------------------
/amplify/.config/project-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "projectName": "gqls3test",
3 | "version": "2.0",
4 | "frontend": "javascript",
5 | "javascript": {
6 | "framework": "react",
7 | "config": {
8 | "SourceDir": "src",
9 | "DistributionDir": "build",
10 | "BuildCommand": "npm run-script build",
11 | "StartCommand": "npm run-script start"
12 | }
13 | },
14 | "providers": [
15 | "awscloudformation"
16 | ]
17 | }
--------------------------------------------------------------------------------
/amplify/backend/api/gqls3test/parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "AppSyncApiName": "gqls3test",
3 | "DynamoDBBillingMode": "PAY_PER_REQUEST",
4 | "AuthCognitoUserPoolId": {
5 | "Fn::GetAtt": [
6 | "authgqls3testeb3f615e",
7 | "Outputs.UserPoolId"
8 | ]
9 | }
10 | }
--------------------------------------------------------------------------------
/amplify/backend/api/gqls3test/schema.graphql:
--------------------------------------------------------------------------------
1 | type User @model {
2 | id: ID!
3 | username: String
4 | visibility: Visibility
5 | avatar: S3Object
6 | }
7 |
8 | type S3Object {
9 | bucket: String!
10 | region: String!
11 | key: String!
12 | }
13 |
14 | enum Visibility {
15 | public
16 | private
17 | }
--------------------------------------------------------------------------------
/amplify/backend/api/gqls3test/stacks/CustomResources.json:
--------------------------------------------------------------------------------
1 | {
2 | "AWSTemplateFormatVersion": "2010-09-09",
3 | "Description": "An auto-generated nested stack.",
4 | "Metadata": {},
5 | "Parameters": {
6 | "AppSyncApiId": {
7 | "Type": "String",
8 | "Description": "The id of the AppSync API associated with this project."
9 | },
10 | "AppSyncApiName": {
11 | "Type": "String",
12 | "Description": "The name of the AppSync API",
13 | "Default": "AppSyncSimpleTransform"
14 | },
15 | "env": {
16 | "Type": "String",
17 | "Description": "The environment name. e.g. Dev, Test, or Production",
18 | "Default": "NONE"
19 | },
20 | "S3DeploymentBucket": {
21 | "Type": "String",
22 | "Description": "The S3 bucket containing all deployment assets for the project."
23 | },
24 | "S3DeploymentRootKey": {
25 | "Type": "String",
26 | "Description": "An S3 key relative to the S3DeploymentBucket that points to the root\nof the deployment directory."
27 | }
28 | },
29 | "Resources": {
30 | "EmptyResource": {
31 | "Type": "Custom::EmptyResource",
32 | "Condition": "AlwaysFalse"
33 | }
34 | },
35 | "Conditions": {
36 | "HasEnvironmentParameter": {
37 | "Fn::Not": [
38 | {
39 | "Fn::Equals": [
40 | {
41 | "Ref": "env"
42 | },
43 | "NONE"
44 | ]
45 | }
46 | ]
47 | },
48 | "AlwaysFalse": {
49 | "Fn::Equals": [
50 | "true",
51 | "false"
52 | ]
53 | }
54 | },
55 | "Outputs": {
56 | "EmptyOutput": {
57 | "Description": "An empty output. You may delete this if you have at least one resource above.",
58 | "Value": ""
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/amplify/backend/auth/gqls3testeb3f615e/gqls3testeb3f615e-cloudformation-template.yml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: 2010-09-09
2 |
3 | Parameters:
4 | env:
5 | Type: String
6 | authRoleName:
7 | Type: String
8 | unauthRoleName:
9 | Type: String
10 | authRoleArn:
11 | Type: String
12 | unauthRoleArn:
13 | Type: String
14 |
15 |
16 | identityPoolName:
17 | Type: String
18 |
19 | allowUnauthenticatedIdentities:
20 | Type: String
21 |
22 | lambdaLogPolicy:
23 | Type: String
24 |
25 | openIdLambdaRoleName:
26 | Type: String
27 |
28 | openIdRolePolicy:
29 | Type: String
30 |
31 | openIdLambdaIAMPolicy:
32 | Type: String
33 |
34 | openIdLogPolicy:
35 | Type: String
36 |
37 | userPoolName:
38 | Type: String
39 |
40 | autoVerifiedAttributes:
41 | Type: CommaDelimitedList
42 |
43 | mfaConfiguration:
44 | Type: String
45 |
46 | mfaTypes:
47 | Type: CommaDelimitedList
48 |
49 | roleName:
50 | Type: String
51 |
52 | roleExternalId:
53 | Type: String
54 |
55 | policyName:
56 | Type: String
57 |
58 | smsAuthenticationMessage:
59 | Type: String
60 |
61 | smsVerificationMessage:
62 | Type: String
63 |
64 | emailVerificationSubject:
65 | Type: String
66 |
67 | emailVerificationMessage:
68 | Type: String
69 |
70 | defaultPasswordPolicy:
71 | Type: String
72 |
73 | passwordPolicyMinLength:
74 | Type: Number
75 |
76 | passwordPolicyCharacters:
77 | Type: CommaDelimitedList
78 |
79 | requiredAttributes:
80 | Type: CommaDelimitedList
81 |
82 | userpoolClientName:
83 | Type: String
84 |
85 | userpoolClientGenerateSecret:
86 | Type: String
87 |
88 | userpoolClientRefreshTokenValidity:
89 | Type: Number
90 |
91 | userpoolClientWriteAttributes:
92 | Type: CommaDelimitedList
93 |
94 | userpoolClientReadAttributes:
95 | Type: CommaDelimitedList
96 |
97 | mfaLambdaRole:
98 | Type: String
99 |
100 | mfaLambdaLogPolicy:
101 | Type: String
102 |
103 | mfaPassRolePolicy:
104 | Type: String
105 |
106 | mfaLambdaIAMPolicy:
107 | Type: String
108 |
109 | userpoolClientLambdaRole:
110 | Type: String
111 |
112 | userpoolClientLogPolicy:
113 | Type: String
114 |
115 | userpoolClientLambdaPolicy:
116 | Type: String
117 |
118 | userpoolClientSetAttributes:
119 | Type: String
120 |
121 | resourceName:
122 | Type: String
123 |
124 | authSelections:
125 | Type: String
126 |
127 | useDefault:
128 | Type: String
129 |
130 | Conditions:
131 | ShouldNotCreateEnvResources: !Equals [ !Ref env, NONE ]
132 |
133 | Resources:
134 |
135 | # BEGIN SNS ROLE RESOURCE
136 | SNSRole:
137 | # Created to allow the UserPool SMS Config to publish via the Simple Notification Service during MFA Process
138 | Type: AWS::IAM::Role
139 | Properties:
140 | RoleName: !If [ShouldNotCreateEnvResources, !Ref roleName, !Join ['',[!Ref roleName, '-', !Ref env]]]
141 | AssumeRolePolicyDocument:
142 | Version: "2012-10-17"
143 | Statement:
144 | - Sid: ""
145 | Effect: "Allow"
146 | Principal:
147 | Service: "cognito-idp.amazonaws.com"
148 | Action:
149 | - "sts:AssumeRole"
150 | Condition:
151 | StringEquals:
152 | sts:ExternalId: !Ref roleExternalId
153 | Policies:
154 | -
155 | PolicyName: !Ref policyName
156 | PolicyDocument:
157 | Version: "2012-10-17"
158 | Statement:
159 | -
160 | Effect: "Allow"
161 | Action:
162 | - "sns:Publish"
163 | Resource: "*"
164 | # BEGIN USER POOL RESOURCES
165 | UserPool:
166 | # Created upon user selection
167 | # Depends on SNS Role for Arn if MFA is enabled
168 | Type: AWS::Cognito::UserPool
169 | UpdateReplacePolicy: Retain
170 | Properties:
171 | UserPoolName: !If [ShouldNotCreateEnvResources, !Ref userPoolName, !Join ['',[!Ref userPoolName, '-', !Ref env]]]
172 |
173 | Schema:
174 |
175 | -
176 | Name: email
177 | Required: true
178 | Mutable: true
179 |
180 |
181 |
182 | AutoVerifiedAttributes: !Ref autoVerifiedAttributes
183 |
184 |
185 | EmailVerificationMessage: !Ref emailVerificationMessage
186 | EmailVerificationSubject: !Ref emailVerificationSubject
187 |
188 | Policies:
189 | PasswordPolicy:
190 | MinimumLength: !Ref passwordPolicyMinLength
191 | RequireLowercase: false
192 | RequireNumbers: false
193 | RequireSymbols: false
194 | RequireUppercase: false
195 |
196 | MfaConfiguration: !Ref mfaConfiguration
197 | SmsVerificationMessage: !Ref smsVerificationMessage
198 | SmsConfiguration:
199 | SnsCallerArn: !GetAtt SNSRole.Arn
200 | ExternalId: !Ref roleExternalId
201 |
202 | UserPoolClientWeb:
203 | # Created provide application access to user pool
204 | # Depends on UserPool for ID reference
205 | Type: "AWS::Cognito::UserPoolClient"
206 | Properties:
207 | ClientName: gqls3teb3f615e_app_clientWeb
208 |
209 | RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity
210 | UserPoolId: !Ref UserPool
211 | DependsOn: UserPool
212 | UserPoolClient:
213 | # Created provide application access to user pool
214 | # Depends on UserPool for ID reference
215 | Type: "AWS::Cognito::UserPoolClient"
216 | Properties:
217 | ClientName: !Ref userpoolClientName
218 |
219 | GenerateSecret: !Ref userpoolClientGenerateSecret
220 | RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity
221 | UserPoolId: !Ref UserPool
222 | DependsOn: UserPool
223 | # BEGIN USER POOL LAMBDA RESOURCES
224 | UserPoolClientRole:
225 | # Created to execute Lambda which gets userpool app client config values
226 | Type: 'AWS::IAM::Role'
227 | Properties:
228 | RoleName: !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',[!Ref userpoolClientLambdaRole, '-', !Ref env]]]
229 | AssumeRolePolicyDocument:
230 | Version: '2012-10-17'
231 | Statement:
232 | - Effect: Allow
233 | Principal:
234 | Service:
235 | - lambda.amazonaws.com
236 | Action:
237 | - 'sts:AssumeRole'
238 | DependsOn: UserPoolClient
239 | UserPoolClientLambda:
240 | # Lambda which gets userpool app client config values
241 | # Depends on UserPool for id
242 | # Depends on UserPoolClientRole for role ARN
243 | Type: 'AWS::Lambda::Function'
244 | Properties:
245 | Code:
246 | ZipFile: !Join
247 | - |+
248 | - - 'const response = require(''cfn-response'');'
249 | - 'const aws = require(''aws-sdk'');'
250 | - 'const identity = new aws.CognitoIdentityServiceProvider();'
251 | - 'exports.handler = (event, context, callback) => {'
252 | - ' if (event.RequestType == ''Delete'') { '
253 | - ' response.send(event, context, response.SUCCESS, {})'
254 | - ' }'
255 | - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {'
256 | - ' const params = {'
257 | - ' ClientId: event.ResourceProperties.clientId,'
258 | - ' UserPoolId: event.ResourceProperties.userpoolId'
259 | - ' };'
260 | - ' identity.describeUserPoolClient(params).promise()'
261 | - ' .then((res) => {'
262 | - ' response.send(event, context, response.SUCCESS, {''appSecret'': res.UserPoolClient.ClientSecret});'
263 | - ' })'
264 | - ' .catch((err) => {'
265 | - ' response.send(event, context, response.FAILED, {err});'
266 | - ' });'
267 | - ' }'
268 | - '};'
269 | Handler: index.handler
270 | Runtime: nodejs8.10
271 | Timeout: '300'
272 | Role: !GetAtt
273 | - UserPoolClientRole
274 | - Arn
275 | DependsOn: UserPoolClientRole
276 | UserPoolClientLambdaPolicy:
277 | # Sets userpool policy for the role that executes the Userpool Client Lambda
278 | # Depends on UserPool for Arn
279 | # Marked as depending on UserPoolClientRole for easier to understand CFN sequencing
280 | Type: 'AWS::IAM::Policy'
281 | Properties:
282 | PolicyName: !Ref userpoolClientLambdaPolicy
283 | Roles:
284 | - !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',[!Ref userpoolClientLambdaRole, '-', !Ref env]]]
285 | PolicyDocument:
286 | Version: '2012-10-17'
287 | Statement:
288 | - Effect: Allow
289 | Action:
290 | - 'cognito-idp:DescribeUserPoolClient'
291 | Resource: !GetAtt UserPool.Arn
292 | DependsOn: UserPoolClientLambda
293 | UserPoolClientLogPolicy:
294 | # Sets log policy for the role that executes the Userpool Client Lambda
295 | # Depends on UserPool for Arn
296 | # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing
297 | Type: 'AWS::IAM::Policy'
298 | Properties:
299 | PolicyName: !Ref userpoolClientLogPolicy
300 | Roles:
301 | - !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',[!Ref userpoolClientLambdaRole, '-', !Ref env]]]
302 | PolicyDocument:
303 | Version: 2012-10-17
304 | Statement:
305 | - Effect: Allow
306 | Action:
307 | - 'logs:CreateLogGroup'
308 | - 'logs:CreateLogStream'
309 | - 'logs:PutLogEvents'
310 | Resource: !Sub
311 | - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:*
312 | - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref UserPoolClientLambda}
313 | DependsOn: UserPoolClientLambdaPolicy
314 | UserPoolClientInputs:
315 | # Values passed to Userpool client Lambda
316 | # Depends on UserPool for Id
317 | # Depends on UserPoolClient for Id
318 | # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing
319 | Type: 'Custom::LambdaCallout'
320 | Properties:
321 | ServiceToken: !GetAtt UserPoolClientLambda.Arn
322 | clientId: !Ref UserPoolClient
323 | userpoolId: !Ref UserPool
324 | DependsOn: UserPoolClientLogPolicy
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 | # BEGIN IDENTITY POOL RESOURCES
333 |
334 |
335 | IdentityPool:
336 | # Always created
337 | Type: AWS::Cognito::IdentityPool
338 | Properties:
339 | IdentityPoolName: !If [ShouldNotCreateEnvResources, 'gqls3testeb3f615e_identitypool_eb3f615e', !Join ['',['gqls3testeb3f615e_identitypool_eb3f615e', '__', !Ref env]]]
340 |
341 | CognitoIdentityProviders:
342 | - ClientId: !Ref UserPoolClient
343 | ProviderName: !Sub
344 | - cognito-idp.${region}.amazonaws.com/${client}
345 | - { region: !Ref "AWS::Region", client: !Ref UserPool}
346 | - ClientId: !Ref UserPoolClientWeb
347 | ProviderName: !Sub
348 | - cognito-idp.${region}.amazonaws.com/${client}
349 | - { region: !Ref "AWS::Region", client: !Ref UserPool}
350 |
351 | AllowUnauthenticatedIdentities: !Ref allowUnauthenticatedIdentities
352 |
353 |
354 | DependsOn: UserPoolClientInputs
355 |
356 |
357 | IdentityPoolRoleMap:
358 | # Created to map Auth and Unauth roles to the identity pool
359 | # Depends on Identity Pool for ID ref
360 | Type: AWS::Cognito::IdentityPoolRoleAttachment
361 | Properties:
362 | IdentityPoolId: !Ref IdentityPool
363 | Roles:
364 | unauthenticated: !Ref unauthRoleArn
365 | authenticated: !Ref authRoleArn
366 | DependsOn: IdentityPool
367 |
368 |
369 | Outputs :
370 |
371 | IdentityPoolId:
372 | Value: !Ref 'IdentityPool'
373 | Description: Id for the identity pool
374 | IdentityPoolName:
375 | Value: !GetAtt IdentityPool.Name
376 |
377 |
378 |
379 |
380 | UserPoolId:
381 | Value: !Ref 'UserPool'
382 | Description: Id for the user pool
383 | UserPoolName:
384 | Value: !Ref userPoolName
385 | AppClientIDWeb:
386 | Value: !Ref 'UserPoolClientWeb'
387 | Description: The user pool app client id for web
388 | AppClientID:
389 | Value: !Ref 'UserPoolClient'
390 | Description: The user pool app client id
391 | AppClientSecret:
392 | Value: !GetAtt UserPoolClientInputs.appSecret
393 |
394 |
395 |
396 |
397 |
398 |
399 |
--------------------------------------------------------------------------------
/amplify/backend/auth/gqls3testeb3f615e/parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "identityPoolName": "gqls3testeb3f615e_identitypool_eb3f615e",
3 | "allowUnauthenticatedIdentities": true,
4 | "lambdaLogPolicy": "gqls3t_eb3f615e_lambda_log_policy",
5 | "openIdLambdaRoleName": "gqls3t_eb3f615e_openid_lambda_role",
6 | "openIdRolePolicy": "gqls3t_eb3f615e_openid_pass_role_policy",
7 | "openIdLambdaIAMPolicy": "gqls3t_eb3f615e_openid_lambda_iam_policy",
8 | "openIdLogPolicy": "gqls3t_eb3f615e_openid_lambda_log_policy",
9 | "userPoolName": "gqls3testeb3f615e_userpool_eb3f615e",
10 | "autoVerifiedAttributes": [
11 | "email"
12 | ],
13 | "mfaConfiguration": "OFF",
14 | "mfaTypes": [
15 | "SMS Text Message"
16 | ],
17 | "roleName": "gqls3teb3f615e_sns-role",
18 | "roleExternalId": "gqls3teb3f615e_role_external_id",
19 | "policyName": "gqls3teb3f615e-sns-policy",
20 | "smsAuthenticationMessage": "Your authentication code is {####}",
21 | "smsVerificationMessage": "Your verification code is {####}",
22 | "emailVerificationSubject": "Your verification code",
23 | "emailVerificationMessage": "Your verification code is {####}",
24 | "defaultPasswordPolicy": false,
25 | "passwordPolicyMinLength": 8,
26 | "passwordPolicyCharacters": [],
27 | "requiredAttributes": [
28 | "email"
29 | ],
30 | "userpoolClientName": "gqls3teb3f615e_app_client",
31 | "userpoolClientGenerateSecret": true,
32 | "userpoolClientRefreshTokenValidity": 30,
33 | "userpoolClientWriteAttributes": [
34 | "email"
35 | ],
36 | "userpoolClientReadAttributes": [
37 | "email"
38 | ],
39 | "mfaLambdaRole": "gqls3teb3f615e_totp_lambda_role",
40 | "mfaLambdaLogPolicy": "gqls3teb3f615e_totp_lambda_log_policy",
41 | "mfaPassRolePolicy": "gqls3teb3f615e_totp_pass_role_policy",
42 | "mfaLambdaIAMPolicy": "gqls3teb3f615e_totp_lambda_iam_policy",
43 | "userpoolClientLambdaRole": "gqls3teb3f615e_userpoolclient_lambda_role",
44 | "userpoolClientLogPolicy": "gqls3teb3f615e_userpoolclient_lambda_log_policy",
45 | "userpoolClientLambdaPolicy": "gqls3teb3f615e_userpoolclient_lambda_iam_policy",
46 | "userpoolClientSetAttributes": false,
47 | "resourceName": "gqls3testeb3f615e",
48 | "authSelections": "identityPoolAndUserPool",
49 | "authRoleName": {
50 | "Ref": "AuthRoleName"
51 | },
52 | "unauthRoleName": {
53 | "Ref": "UnauthRoleName"
54 | },
55 | "authRoleArn": {
56 | "Fn::GetAtt": [
57 | "AuthRole",
58 | "Arn"
59 | ]
60 | },
61 | "unauthRoleArn": {
62 | "Fn::GetAtt": [
63 | "UnauthRole",
64 | "Arn"
65 | ]
66 | },
67 | "useDefault": "default"
68 | }
--------------------------------------------------------------------------------
/amplify/backend/backend-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "auth": {
3 | "gqls3testeb3f615e": {
4 | "service": "Cognito",
5 | "providerPlugin": "awscloudformation"
6 | }
7 | },
8 | "storage": {
9 | "gqls3test": {
10 | "service": "S3",
11 | "providerPlugin": "awscloudformation"
12 | }
13 | },
14 | "api": {
15 | "gqls3test": {
16 | "service": "AppSync",
17 | "providerPlugin": "awscloudformation",
18 | "output": {
19 | "securityType": "AMAZON_COGNITO_USER_POOLS"
20 | }
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/amplify/backend/storage/gqls3test/parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "bucketName": "gqls3test9cf440e7c85b495793505c36abdf365a",
3 | "authPolicyName": "s3_amplify_5c16ce3b",
4 | "unauthPolicyName": "s3_amplify_5c16ce3b",
5 | "authRoleName": {
6 | "Ref": "AuthRoleName"
7 | },
8 | "unauthRoleName": {
9 | "Ref": "UnauthRoleName"
10 | },
11 | "selectedGuestPermissions": [
12 | "s3:GetObject",
13 | "s3:ListBucket"
14 | ],
15 | "selectedAuthenticatedPermissions": [
16 | "s3:PutObject",
17 | "s3:GetObject",
18 | "s3:ListBucket",
19 | "s3:DeleteObject"
20 | ],
21 | "s3PermissionsAuthenticatedPublic": "s3:PutObject,s3:GetObject,s3:DeleteObject",
22 | "s3PublicPolicy": "Public_policy_7ec660c0",
23 | "s3PermissionsAuthenticatedUploads": "s3:PutObject",
24 | "s3UploadsPolicy": "Uploads_policy_7ec660c0",
25 | "s3PermissionsAuthenticatedProtected": "s3:PutObject,s3:GetObject,s3:DeleteObject",
26 | "s3ProtectedPolicy": "Protected_policy_cca4785b",
27 | "s3PermissionsAuthenticatedPrivate": "s3:PutObject,s3:GetObject,s3:DeleteObject",
28 | "s3PrivatePolicy": "Private_policy_cca4785b",
29 | "AuthenticatedAllowList": "ALLOW",
30 | "s3ReadPolicy": "read_policy_7ec660c0",
31 | "s3PermissionsGuestPublic": "s3:GetObject",
32 | "s3PermissionsGuestUploads": "DISALLOW",
33 | "GuestAllowList": "ALLOW"
34 | }
--------------------------------------------------------------------------------
/amplify/backend/storage/gqls3test/s3-cloudformation-template.json:
--------------------------------------------------------------------------------
1 | {
2 | "AWSTemplateFormatVersion": "2010-09-09",
3 | "Description": "S3 resource stack creation using Amplify CLI",
4 | "Parameters": {
5 | "bucketName": {
6 | "Type": "String"
7 | },
8 | "authPolicyName": {
9 | "Type": "String"
10 | },
11 | "unauthPolicyName": {
12 | "Type": "String"
13 | },
14 | "authRoleName": {
15 | "Type": "String"
16 | },
17 | "unauthRoleName": {
18 | "Type": "String"
19 | },
20 | "s3PublicPolicy": {
21 | "Type": "String"
22 | },
23 | "s3PrivatePolicy": {
24 | "Type": "String"
25 | },
26 | "s3ProtectedPolicy": {
27 | "Type": "String"
28 | },
29 | "s3UploadsPolicy": {
30 | "Type": "String"
31 | },
32 | "s3ReadPolicy": {
33 | "Type": "String"
34 | },
35 | "s3PermissionsAuthenticatedPublic": {
36 | "Type": "String"
37 | },
38 | "s3PermissionsAuthenticatedProtected": {
39 | "Type": "String"
40 | },
41 | "s3PermissionsAuthenticatedPrivate": {
42 | "Type": "String"
43 | },
44 | "s3PermissionsAuthenticatedUploads": {
45 | "Type": "String"
46 | },
47 | "s3PermissionsGuestPublic": {
48 | "Type": "String",
49 | "Default" : "DISALLOW"
50 | },
51 | "s3PermissionsGuestUploads": {
52 | "Type": "String",
53 | "Default" : "DISALLOW" },
54 | "AuthenticatedAllowList": {
55 | "Type": "String"
56 | },
57 | "GuestAllowList": {
58 | "Type": "String",
59 | "Default" : "DISALLOW"
60 | },
61 | "selectedGuestPermissions": {
62 | "Type": "CommaDelimitedList"
63 | },
64 | "selectedAuthenticatedPermissions": {
65 | "Type": "CommaDelimitedList"
66 | },
67 | "env": {
68 | "Type": "String"
69 | }
70 | },
71 | "Conditions": {
72 | "ShouldNotCreateEnvResources": {
73 | "Fn::Equals": [
74 | {
75 | "Ref": "env"
76 | },
77 | "NONE"
78 | ]
79 | },
80 | "CreateAuthPublic": {
81 | "Fn::Not" : [{
82 | "Fn::Equals" : [
83 | {"Ref" : "s3PermissionsAuthenticatedPublic"},
84 | "DISALLOW"
85 | ]
86 | }]
87 | },
88 | "CreateAuthProtected": {
89 | "Fn::Not" : [{
90 | "Fn::Equals" : [
91 | {"Ref" : "s3PermissionsAuthenticatedProtected"},
92 | "DISALLOW"
93 | ]
94 | }]
95 | },
96 | "CreateAuthPrivate": {
97 | "Fn::Not" : [{
98 | "Fn::Equals" : [
99 | {"Ref" : "s3PermissionsAuthenticatedPrivate"},
100 | "DISALLOW"
101 | ]
102 | }]
103 | },
104 | "CreateAuthUploads": {
105 | "Fn::Not" : [{
106 | "Fn::Equals" : [
107 | {"Ref" : "s3PermissionsAuthenticatedUploads"},
108 | "DISALLOW"
109 | ]
110 | }]
111 | },
112 | "CreateGuestPublic": {
113 | "Fn::Not" : [{
114 | "Fn::Equals" : [
115 | {"Ref" : "s3PermissionsGuestPublic"},
116 | "DISALLOW"
117 | ]
118 | }]
119 | },
120 | "CreateGuestUploads": {
121 | "Fn::Not" : [{
122 | "Fn::Equals" : [
123 | {"Ref" : "s3PermissionsGuestUploads"},
124 | "DISALLOW"
125 | ]
126 | }]
127 | },
128 | "AuthReadAndList": {
129 | "Fn::Not" : [{
130 | "Fn::Equals" : [
131 | {"Ref" : "AuthenticatedAllowList"},
132 | "DISALLOW"
133 | ]
134 | }]
135 | },
136 | "GuestReadAndList": {
137 | "Fn::Not" : [{
138 | "Fn::Equals" : [
139 | {"Ref" : "GuestAllowList"},
140 | "DISALLOW"
141 | ]
142 | }]
143 | }
144 | },
145 | "Resources": {
146 | "S3Bucket": {
147 | "Type": "AWS::S3::Bucket",
148 | "DeletionPolicy" : "Retain",
149 | "Properties": {
150 | "BucketName": {
151 | "Fn::If": [
152 | "ShouldNotCreateEnvResources",
153 | {
154 | "Ref": "bucketName"
155 | },
156 | {
157 | "Fn::Join": [
158 | "",
159 | [
160 | {
161 | "Ref": "bucketName"
162 | },
163 | "-",
164 | {
165 | "Ref": "env"
166 | }
167 | ]
168 | ]
169 | }
170 | ]
171 | },
172 | "CorsConfiguration": {
173 | "CorsRules": [
174 | {
175 | "AllowedHeaders": [
176 | "*"
177 | ],
178 | "AllowedMethods": [
179 | "GET",
180 | "HEAD",
181 | "PUT",
182 | "POST",
183 | "DELETE"
184 | ],
185 | "AllowedOrigins": [
186 | "*"
187 | ],
188 | "ExposedHeaders": [
189 | "x-amz-server-side-encryption",
190 | "x-amz-request-id",
191 | "x-amz-id-2",
192 | "ETag"
193 | ],
194 | "Id": "S3CORSRuleId1",
195 | "MaxAge": "3000"
196 | }
197 | ]
198 | }
199 | }
200 | },
201 | "S3AuthPublicPolicy": {
202 | "DependsOn": [
203 | "S3Bucket"
204 | ],
205 | "Condition": "CreateAuthPublic",
206 | "Type": "AWS::IAM::Policy",
207 | "Properties": {
208 | "PolicyName": {
209 | "Ref": "s3PublicPolicy"
210 | },
211 | "Roles": [
212 | {
213 | "Ref": "authRoleName"
214 | }
215 | ],
216 | "PolicyDocument": {
217 | "Version": "2012-10-17",
218 | "Statement": [
219 | {
220 | "Effect": "Allow",
221 | "Action": {
222 | "Fn::Split" : [ "," , {
223 | "Ref": "s3PermissionsAuthenticatedPublic"
224 | } ]
225 | },
226 | "Resource": [
227 | {
228 | "Fn::Join": [
229 | "",
230 | [
231 | "arn:aws:s3:::",
232 | {
233 | "Ref": "S3Bucket"
234 | },
235 | "/public/*"
236 | ]
237 | ]
238 | }
239 | ]
240 | }
241 | ]
242 | }
243 | }
244 | },
245 | "S3AuthProtectedPolicy": {
246 | "DependsOn": [
247 | "S3Bucket"
248 | ],
249 | "Condition": "CreateAuthProtected",
250 | "Type": "AWS::IAM::Policy",
251 | "Properties": {
252 | "PolicyName": {
253 | "Ref": "s3ProtectedPolicy"
254 | },
255 | "Roles": [
256 | {
257 | "Ref": "authRoleName"
258 | }
259 | ],
260 | "PolicyDocument": {
261 | "Version": "2012-10-17",
262 | "Statement": [
263 | {
264 | "Effect": "Allow",
265 | "Action": {
266 | "Fn::Split" : [ "," , {
267 | "Ref": "s3PermissionsAuthenticatedProtected"
268 | } ]
269 | },
270 | "Resource": [
271 | {
272 | "Fn::Join": [
273 | "",
274 | [
275 | "arn:aws:s3:::",
276 | {
277 | "Ref": "S3Bucket"
278 | },
279 | "/protected/${cognito-identity.amazonaws.com:sub}/*"
280 | ]
281 | ]
282 | }
283 | ]
284 | }
285 | ]
286 | }
287 | }
288 | },
289 | "S3AuthPrivatePolicy": {
290 | "DependsOn": [
291 | "S3Bucket"
292 | ],
293 | "Condition": "CreateAuthPrivate",
294 | "Type": "AWS::IAM::Policy",
295 | "Properties": {
296 | "PolicyName": {
297 | "Ref": "s3PrivatePolicy"
298 | },
299 | "Roles": [
300 | {
301 | "Ref": "authRoleName"
302 | }
303 | ],
304 | "PolicyDocument": {
305 | "Version": "2012-10-17",
306 | "Statement": [
307 | {
308 | "Effect": "Allow",
309 | "Action": {
310 | "Fn::Split" : [ "," , {
311 | "Ref": "s3PermissionsAuthenticatedPrivate"
312 | } ]
313 | },
314 | "Resource": [
315 | {
316 | "Fn::Join": [
317 | "",
318 | [
319 | "arn:aws:s3:::",
320 | {
321 | "Ref": "S3Bucket"
322 | },
323 | "/private/${cognito-identity.amazonaws.com:sub}/*"
324 | ]
325 | ]
326 | }
327 | ]
328 | }
329 | ]
330 | }
331 | }
332 | },
333 | "S3AuthUploadPolicy": {
334 | "DependsOn": [
335 | "S3Bucket"
336 | ],
337 | "Condition": "CreateAuthUploads",
338 | "Type": "AWS::IAM::Policy",
339 | "Properties": {
340 | "PolicyName": {
341 | "Ref": "s3UploadsPolicy"
342 | },
343 | "Roles": [
344 | {
345 | "Ref": "authRoleName"
346 | }
347 | ],
348 | "PolicyDocument": {
349 | "Version": "2012-10-17",
350 | "Statement": [
351 | {
352 | "Effect": "Allow",
353 | "Action": {
354 | "Fn::Split" : [ "," , {
355 | "Ref": "s3PermissionsAuthenticatedUploads"
356 | } ]
357 | },
358 | "Resource": [
359 | {
360 | "Fn::Join": [
361 | "",
362 | [
363 | "arn:aws:s3:::",
364 | {
365 | "Ref": "S3Bucket"
366 | },
367 | "/uploads/*"
368 | ]
369 | ]
370 | }
371 | ]
372 | }
373 | ]
374 | }
375 | }
376 | },
377 | "S3AuthReadPolicy": {
378 | "DependsOn": [
379 | "S3Bucket"
380 | ],
381 | "Condition": "AuthReadAndList",
382 | "Type": "AWS::IAM::Policy",
383 | "Properties": {
384 | "PolicyName": {
385 | "Ref": "s3ReadPolicy"
386 | },
387 | "Roles": [
388 | {
389 | "Ref": "authRoleName"
390 | }
391 | ],
392 | "PolicyDocument": {
393 | "Version": "2012-10-17",
394 | "Statement": [
395 | {
396 | "Effect": "Allow",
397 | "Action": [
398 | "s3:GetObject"
399 | ],
400 | "Resource": [
401 | {
402 | "Fn::Join": [
403 | "",
404 | [
405 | "arn:aws:s3:::",
406 | {
407 | "Ref": "S3Bucket"
408 | },
409 | "/protected/*"
410 | ]
411 | ]
412 | }
413 | ]
414 | },
415 | {
416 | "Effect": "Allow",
417 | "Action": [
418 | "s3:ListBucket"
419 | ],
420 | "Resource": [
421 | {
422 | "Fn::Join": [
423 | "",
424 | [
425 | "arn:aws:s3:::",
426 | {
427 | "Ref": "S3Bucket"
428 | }
429 | ]
430 | ]
431 | }
432 | ],
433 | "Condition": {
434 | "StringLike": {
435 | "s3:prefix": [
436 | "public/",
437 | "public/*",
438 | "protected/",
439 | "protected/*",
440 | "private/${cognito-identity.amazonaws.com:sub}/",
441 | "private/${cognito-identity.amazonaws.com:sub}/*"
442 | ]
443 | }
444 | }
445 | }
446 | ]
447 | }
448 | }
449 | },
450 | "S3GuestPublicPolicy": {
451 | "DependsOn": [
452 | "S3Bucket"
453 | ],
454 | "Condition": "CreateGuestPublic",
455 | "Type": "AWS::IAM::Policy",
456 | "Properties": {
457 | "PolicyName": {
458 | "Ref": "s3PublicPolicy"
459 | },
460 | "Roles": [
461 | {
462 | "Ref": "unauthRoleName"
463 | }
464 | ],
465 | "PolicyDocument": {
466 | "Version": "2012-10-17",
467 | "Statement": [
468 | {
469 | "Effect": "Allow",
470 | "Action": {
471 | "Fn::Split" : [ "," , {
472 | "Ref": "s3PermissionsGuestPublic"
473 | } ]
474 | },
475 | "Resource": [
476 | {
477 | "Fn::Join": [
478 | "",
479 | [
480 | "arn:aws:s3:::",
481 | {
482 | "Ref": "S3Bucket"
483 | },
484 | "/public/*"
485 | ]
486 | ]
487 | }
488 | ]
489 | }
490 | ]
491 | }
492 | }
493 | },
494 | "S3GuestUploadPolicy": {
495 | "DependsOn": [
496 | "S3Bucket"
497 | ],
498 | "Condition": "CreateGuestUploads",
499 | "Type": "AWS::IAM::Policy",
500 | "Properties": {
501 | "PolicyName": {
502 | "Ref": "s3UploadsPolicy"
503 | },
504 | "Roles": [
505 | {
506 | "Ref": "unauthRoleName"
507 | }
508 | ],
509 | "PolicyDocument": {
510 | "Version": "2012-10-17",
511 | "Statement": [
512 | {
513 | "Effect": "Allow",
514 | "Action": {
515 | "Fn::Split" : [ "," , {
516 | "Ref": "s3PermissionsGuestUploads"
517 | } ]
518 | },
519 | "Resource": [
520 | {
521 | "Fn::Join": [
522 | "",
523 | [
524 | "arn:aws:s3:::",
525 | {
526 | "Ref": "S3Bucket"
527 | },
528 | "/uploads/*"
529 | ]
530 | ]
531 | }
532 | ]
533 | }
534 | ]
535 | }
536 | }
537 | },
538 | "S3GuestReadPolicy": {
539 | "DependsOn": [
540 | "S3Bucket"
541 | ],
542 | "Condition": "GuestReadAndList",
543 | "Type": "AWS::IAM::Policy",
544 | "Properties": {
545 | "PolicyName": {
546 | "Ref": "s3ReadPolicy"
547 | },
548 | "Roles": [
549 | {
550 | "Ref": "unauthRoleName"
551 | }
552 | ],
553 | "PolicyDocument": {
554 | "Version": "2012-10-17",
555 | "Statement": [
556 | {
557 | "Effect": "Allow",
558 | "Action": [
559 | "s3:GetObject"
560 | ],
561 | "Resource": [
562 | {
563 | "Fn::Join": [
564 | "",
565 | [
566 | "arn:aws:s3:::",
567 | {
568 | "Ref": "S3Bucket"
569 | },
570 | "/protected/*"
571 | ]
572 | ]
573 | }
574 | ]
575 | },
576 | {
577 | "Effect": "Allow",
578 | "Action": [
579 | "s3:ListBucket"
580 | ],
581 | "Resource": [
582 | {
583 | "Fn::Join": [
584 | "",
585 | [
586 | "arn:aws:s3:::",
587 | {
588 | "Ref": "S3Bucket"
589 | }
590 | ]
591 | ]
592 | }
593 | ],
594 | "Condition": {
595 | "StringLike": {
596 | "s3:prefix": [
597 | "public/",
598 | "public/*",
599 | "protected/",
600 | "protected/*"
601 | ]
602 | }
603 | }
604 | }
605 | ]
606 | }
607 | }
608 | }
609 | },
610 | "Outputs": {
611 | "BucketName": {
612 | "Value": {
613 | "Ref": "S3Bucket"
614 | },
615 | "Description": "Bucket name for the S3 bucket"
616 | },
617 | "Region": {
618 | "Value": {
619 | "Ref": "AWS::Region"
620 | }
621 | }
622 | }
623 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gqls3test",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "aws-amplify": "^1.1.29",
7 | "aws-amplify-react": "^2.3.9",
8 | "react": "^16.8.6",
9 | "react-dom": "^16.8.6",
10 | "react-scripts": "3.0.1",
11 | "uuid": "^3.3.2"
12 | },
13 | "scripts": {
14 | "start": "react-scripts start",
15 | "build": "react-scripts build",
16 | "test": "react-scripts test",
17 | "eject": "react-scripts eject"
18 | },
19 | "eslintConfig": {
20 | "extends": "react-app"
21 | },
22 | "browserslist": {
23 | "production": [
24 | ">0.2%",
25 | "not dead",
26 | "not op_mini all"
27 | ],
28 | "development": [
29 | "last 1 chrome version",
30 | "last 1 firefox version",
31 | "last 1 safari version"
32 | ]
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dabit3/react-appsync-graphql-images-s3/76cb213bb2685e6b626970923638e89ea4cc6076/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
22 | React App
23 |
24 |
25 |
26 |
27 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 40vmin;
8 | pointer-events: none;
9 | }
10 |
11 | .App-header {
12 | background-color: #282c34;
13 | min-height: 100vh;
14 | display: flex;
15 | flex-direction: column;
16 | align-items: center;
17 | justify-content: center;
18 | font-size: calc(10px + 2vmin);
19 | color: white;
20 | }
21 |
22 | .App-link {
23 | color: #61dafb;
24 | }
25 |
26 | @keyframes App-logo-spin {
27 | from {
28 | transform: rotate(0deg);
29 | }
30 | to {
31 | transform: rotate(360deg);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useReducer, useEffect } from 'react'
2 | import './App.css'
3 | import { withAuthenticator } from 'aws-amplify-react'
4 | import { Storage, Auth, API, graphqlOperation } from 'aws-amplify'
5 | import uuid from 'uuid/v4'
6 | import { createUser } from './graphql/mutations'
7 | import { listUsers } from './graphql/queries'
8 | import { onCreateUser } from './graphql/subscriptions'
9 | import ampConfig from './aws-exports'
10 |
11 | const {
12 | aws_user_files_s3_bucket_region: region,
13 | aws_user_files_s3_bucket: bucket
14 | } = ampConfig
15 |
16 | const initialState = {
17 | users: []
18 | }
19 |
20 | function reducer(state, action) {
21 | switch(action.type) {
22 | case 'SET_USERS':
23 | return { ...state, users: action.users }
24 | case 'ADD_USER':
25 | return { ...state, users: [action.user, ...state.users] }
26 | default:
27 | return state
28 | }
29 | }
30 |
31 | function App() {
32 | const [file, updateFile] = useState({})
33 | const [state, dispatch] = useReducer(reducer, initialState)
34 |
35 | function handleChange(event) {
36 | const { target: { value, files } } = event
37 | const [image] = files || []
38 | updateFile(image || value)
39 | }
40 |
41 | async function fetchUsers() {
42 | try {
43 | // fetch all items from DB
44 | let users = await API.graphql(graphqlOperation(listUsers))
45 | users = users.data.listUsers.items
46 | // create Amazon S3 api calls for items in list
47 | const userRequests = users.map(u => Storage.get(u.avatar.key))
48 | // get signed Image URLs from S3 for each item in array by making the API call
49 | const userData = await(Promise.all(userRequests))
50 | // add new signed url to each item in array
51 | users.forEach((u, i) => {
52 | u.avatarUrl = userData[i]
53 | })
54 | dispatch({ type: 'SET_USERS', users })
55 | } catch(err) {
56 | console.log('error fetching users')
57 | }
58 | }
59 |
60 | async function handleSubmit(event) {
61 | event.preventDefault()
62 | const { identityId } = await Auth.currentCredentials()
63 | const { username } = await Auth.currentUserInfo()
64 |
65 | if (file) {
66 | const { name: fileName, type: mimeType } = file
67 | const key = `${identityId}/${uuid()}${fileName}`
68 | const fileForUpload = {
69 | bucket,
70 | key,
71 | region,
72 | }
73 | const inputData = { username, avatar: fileForUpload }
74 |
75 | try {
76 | await Storage.put(key, file, {
77 | contentType: mimeType
78 | })
79 | await API.graphql(graphqlOperation(createUser, { input: inputData }))
80 | console.log('successfully stored user data!')
81 | } catch (err) {
82 | console.log('error: ', err)
83 | }
84 | }
85 | }
86 | useEffect(() => {
87 | fetchUsers()
88 | const subscription = API.graphql(graphqlOperation(onCreateUser))
89 | .subscribe({
90 | next: async userData => {
91 | const { onCreateUser } = userData.value.data
92 | const avatarUrl = await Storage.get(onCreateUser.avatar.key)
93 | onCreateUser['avatarUrl'] = avatarUrl
94 | dispatch({ type: 'ADD_USER', user: onCreateUser })
95 | }
96 | })
97 | return () => subscription.unsubscribe()
98 | }, [])
99 |
100 | return (
101 |
102 |
108 |
111 | {
112 | state.users.map((u, i) => {
113 | return (
114 |

119 | )
120 | })
121 | }
122 |
123 | )
124 | }
125 |
126 | const styles = {
127 | container: {
128 | width: 100,
129 | margin: '0 auto'
130 | },
131 | button: {
132 | width: 200,
133 | backgroundColor: '#ddd',
134 | cursor: 'pointer',
135 | height: 30,
136 | margin: '0px 0px 8px'
137 | }
138 | }
139 |
140 | export default withAuthenticator(App, { includeGreetings: true })
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/src/graphql/mutations.js:
--------------------------------------------------------------------------------
1 | // eslint-disable
2 | // this is an auto generated file. This will be overwritten
3 |
4 | export const createUser = `mutation CreateUser($input: CreateUserInput!) {
5 | createUser(input: $input) {
6 | id
7 | username
8 | visibility
9 | avatar {
10 | bucket
11 | region
12 | key
13 | }
14 | }
15 | }
16 | `;
17 | export const updateUser = `mutation UpdateUser($input: UpdateUserInput!) {
18 | updateUser(input: $input) {
19 | id
20 | username
21 | visibility
22 | avatar {
23 | bucket
24 | region
25 | key
26 | }
27 | }
28 | }
29 | `;
30 | export const deleteUser = `mutation DeleteUser($input: DeleteUserInput!) {
31 | deleteUser(input: $input) {
32 | id
33 | username
34 | visibility
35 | avatar {
36 | bucket
37 | region
38 | key
39 | }
40 | }
41 | }
42 | `;
43 |
--------------------------------------------------------------------------------
/src/graphql/queries.js:
--------------------------------------------------------------------------------
1 | // eslint-disable
2 | // this is an auto generated file. This will be overwritten
3 |
4 | export const getUser = `query GetUser($id: ID!) {
5 | getUser(id: $id) {
6 | id
7 | username
8 | visibility
9 | avatar {
10 | bucket
11 | region
12 | key
13 | }
14 | }
15 | }
16 | `;
17 | export const listUsers = `query ListUsers(
18 | $filter: ModelUserFilterInput
19 | $limit: Int
20 | $nextToken: String
21 | ) {
22 | listUsers(filter: $filter, limit: $limit, nextToken: $nextToken) {
23 | items {
24 | id
25 | username
26 | visibility
27 | avatar {
28 | bucket
29 | region
30 | key
31 | }
32 | }
33 | nextToken
34 | }
35 | }
36 | `;
37 |
--------------------------------------------------------------------------------
/src/graphql/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "data" : {
3 | "__schema" : {
4 | "queryType" : {
5 | "name" : "Query"
6 | },
7 | "mutationType" : {
8 | "name" : "Mutation"
9 | },
10 | "subscriptionType" : {
11 | "name" : "Subscription"
12 | },
13 | "types" : [ {
14 | "kind" : "OBJECT",
15 | "name" : "Query",
16 | "description" : null,
17 | "fields" : [ {
18 | "name" : "getUser",
19 | "description" : null,
20 | "args" : [ {
21 | "name" : "id",
22 | "description" : null,
23 | "type" : {
24 | "kind" : "NON_NULL",
25 | "name" : null,
26 | "ofType" : {
27 | "kind" : "SCALAR",
28 | "name" : "ID",
29 | "ofType" : null
30 | }
31 | },
32 | "defaultValue" : null
33 | } ],
34 | "type" : {
35 | "kind" : "OBJECT",
36 | "name" : "User",
37 | "ofType" : null
38 | },
39 | "isDeprecated" : false,
40 | "deprecationReason" : null
41 | }, {
42 | "name" : "listUsers",
43 | "description" : null,
44 | "args" : [ {
45 | "name" : "filter",
46 | "description" : null,
47 | "type" : {
48 | "kind" : "INPUT_OBJECT",
49 | "name" : "ModelUserFilterInput",
50 | "ofType" : null
51 | },
52 | "defaultValue" : null
53 | }, {
54 | "name" : "limit",
55 | "description" : null,
56 | "type" : {
57 | "kind" : "SCALAR",
58 | "name" : "Int",
59 | "ofType" : null
60 | },
61 | "defaultValue" : null
62 | }, {
63 | "name" : "nextToken",
64 | "description" : null,
65 | "type" : {
66 | "kind" : "SCALAR",
67 | "name" : "String",
68 | "ofType" : null
69 | },
70 | "defaultValue" : null
71 | } ],
72 | "type" : {
73 | "kind" : "OBJECT",
74 | "name" : "ModelUserConnection",
75 | "ofType" : null
76 | },
77 | "isDeprecated" : false,
78 | "deprecationReason" : null
79 | } ],
80 | "inputFields" : null,
81 | "interfaces" : [ ],
82 | "enumValues" : null,
83 | "possibleTypes" : null
84 | }, {
85 | "kind" : "OBJECT",
86 | "name" : "User",
87 | "description" : null,
88 | "fields" : [ {
89 | "name" : "id",
90 | "description" : null,
91 | "args" : [ ],
92 | "type" : {
93 | "kind" : "NON_NULL",
94 | "name" : null,
95 | "ofType" : {
96 | "kind" : "SCALAR",
97 | "name" : "ID",
98 | "ofType" : null
99 | }
100 | },
101 | "isDeprecated" : false,
102 | "deprecationReason" : null
103 | }, {
104 | "name" : "username",
105 | "description" : null,
106 | "args" : [ ],
107 | "type" : {
108 | "kind" : "SCALAR",
109 | "name" : "String",
110 | "ofType" : null
111 | },
112 | "isDeprecated" : false,
113 | "deprecationReason" : null
114 | }, {
115 | "name" : "visibility",
116 | "description" : null,
117 | "args" : [ ],
118 | "type" : {
119 | "kind" : "ENUM",
120 | "name" : "Visibility",
121 | "ofType" : null
122 | },
123 | "isDeprecated" : false,
124 | "deprecationReason" : null
125 | }, {
126 | "name" : "avatar",
127 | "description" : null,
128 | "args" : [ ],
129 | "type" : {
130 | "kind" : "OBJECT",
131 | "name" : "S3Object",
132 | "ofType" : null
133 | },
134 | "isDeprecated" : false,
135 | "deprecationReason" : null
136 | } ],
137 | "inputFields" : null,
138 | "interfaces" : [ ],
139 | "enumValues" : null,
140 | "possibleTypes" : null
141 | }, {
142 | "kind" : "SCALAR",
143 | "name" : "ID",
144 | "description" : "Built-in ID",
145 | "fields" : null,
146 | "inputFields" : null,
147 | "interfaces" : null,
148 | "enumValues" : null,
149 | "possibleTypes" : null
150 | }, {
151 | "kind" : "SCALAR",
152 | "name" : "String",
153 | "description" : "Built-in String",
154 | "fields" : null,
155 | "inputFields" : null,
156 | "interfaces" : null,
157 | "enumValues" : null,
158 | "possibleTypes" : null
159 | }, {
160 | "kind" : "ENUM",
161 | "name" : "Visibility",
162 | "description" : null,
163 | "fields" : null,
164 | "inputFields" : null,
165 | "interfaces" : null,
166 | "enumValues" : [ {
167 | "name" : "public",
168 | "description" : null,
169 | "isDeprecated" : false,
170 | "deprecationReason" : null
171 | }, {
172 | "name" : "private",
173 | "description" : null,
174 | "isDeprecated" : false,
175 | "deprecationReason" : null
176 | } ],
177 | "possibleTypes" : null
178 | }, {
179 | "kind" : "OBJECT",
180 | "name" : "S3Object",
181 | "description" : null,
182 | "fields" : [ {
183 | "name" : "bucket",
184 | "description" : null,
185 | "args" : [ ],
186 | "type" : {
187 | "kind" : "NON_NULL",
188 | "name" : null,
189 | "ofType" : {
190 | "kind" : "SCALAR",
191 | "name" : "String",
192 | "ofType" : null
193 | }
194 | },
195 | "isDeprecated" : false,
196 | "deprecationReason" : null
197 | }, {
198 | "name" : "region",
199 | "description" : null,
200 | "args" : [ ],
201 | "type" : {
202 | "kind" : "NON_NULL",
203 | "name" : null,
204 | "ofType" : {
205 | "kind" : "SCALAR",
206 | "name" : "String",
207 | "ofType" : null
208 | }
209 | },
210 | "isDeprecated" : false,
211 | "deprecationReason" : null
212 | }, {
213 | "name" : "key",
214 | "description" : null,
215 | "args" : [ ],
216 | "type" : {
217 | "kind" : "NON_NULL",
218 | "name" : null,
219 | "ofType" : {
220 | "kind" : "SCALAR",
221 | "name" : "String",
222 | "ofType" : null
223 | }
224 | },
225 | "isDeprecated" : false,
226 | "deprecationReason" : null
227 | } ],
228 | "inputFields" : null,
229 | "interfaces" : [ ],
230 | "enumValues" : null,
231 | "possibleTypes" : null
232 | }, {
233 | "kind" : "OBJECT",
234 | "name" : "ModelUserConnection",
235 | "description" : null,
236 | "fields" : [ {
237 | "name" : "items",
238 | "description" : null,
239 | "args" : [ ],
240 | "type" : {
241 | "kind" : "LIST",
242 | "name" : null,
243 | "ofType" : {
244 | "kind" : "OBJECT",
245 | "name" : "User",
246 | "ofType" : null
247 | }
248 | },
249 | "isDeprecated" : false,
250 | "deprecationReason" : null
251 | }, {
252 | "name" : "nextToken",
253 | "description" : null,
254 | "args" : [ ],
255 | "type" : {
256 | "kind" : "SCALAR",
257 | "name" : "String",
258 | "ofType" : null
259 | },
260 | "isDeprecated" : false,
261 | "deprecationReason" : null
262 | } ],
263 | "inputFields" : null,
264 | "interfaces" : [ ],
265 | "enumValues" : null,
266 | "possibleTypes" : null
267 | }, {
268 | "kind" : "INPUT_OBJECT",
269 | "name" : "ModelUserFilterInput",
270 | "description" : null,
271 | "fields" : null,
272 | "inputFields" : [ {
273 | "name" : "id",
274 | "description" : null,
275 | "type" : {
276 | "kind" : "INPUT_OBJECT",
277 | "name" : "ModelIDFilterInput",
278 | "ofType" : null
279 | },
280 | "defaultValue" : null
281 | }, {
282 | "name" : "username",
283 | "description" : null,
284 | "type" : {
285 | "kind" : "INPUT_OBJECT",
286 | "name" : "ModelStringFilterInput",
287 | "ofType" : null
288 | },
289 | "defaultValue" : null
290 | }, {
291 | "name" : "visibility",
292 | "description" : null,
293 | "type" : {
294 | "kind" : "INPUT_OBJECT",
295 | "name" : "ModelVisibilityFilterInput",
296 | "ofType" : null
297 | },
298 | "defaultValue" : null
299 | }, {
300 | "name" : "and",
301 | "description" : null,
302 | "type" : {
303 | "kind" : "LIST",
304 | "name" : null,
305 | "ofType" : {
306 | "kind" : "INPUT_OBJECT",
307 | "name" : "ModelUserFilterInput",
308 | "ofType" : null
309 | }
310 | },
311 | "defaultValue" : null
312 | }, {
313 | "name" : "or",
314 | "description" : null,
315 | "type" : {
316 | "kind" : "LIST",
317 | "name" : null,
318 | "ofType" : {
319 | "kind" : "INPUT_OBJECT",
320 | "name" : "ModelUserFilterInput",
321 | "ofType" : null
322 | }
323 | },
324 | "defaultValue" : null
325 | }, {
326 | "name" : "not",
327 | "description" : null,
328 | "type" : {
329 | "kind" : "INPUT_OBJECT",
330 | "name" : "ModelUserFilterInput",
331 | "ofType" : null
332 | },
333 | "defaultValue" : null
334 | } ],
335 | "interfaces" : null,
336 | "enumValues" : null,
337 | "possibleTypes" : null
338 | }, {
339 | "kind" : "INPUT_OBJECT",
340 | "name" : "ModelIDFilterInput",
341 | "description" : null,
342 | "fields" : null,
343 | "inputFields" : [ {
344 | "name" : "ne",
345 | "description" : null,
346 | "type" : {
347 | "kind" : "SCALAR",
348 | "name" : "ID",
349 | "ofType" : null
350 | },
351 | "defaultValue" : null
352 | }, {
353 | "name" : "eq",
354 | "description" : null,
355 | "type" : {
356 | "kind" : "SCALAR",
357 | "name" : "ID",
358 | "ofType" : null
359 | },
360 | "defaultValue" : null
361 | }, {
362 | "name" : "le",
363 | "description" : null,
364 | "type" : {
365 | "kind" : "SCALAR",
366 | "name" : "ID",
367 | "ofType" : null
368 | },
369 | "defaultValue" : null
370 | }, {
371 | "name" : "lt",
372 | "description" : null,
373 | "type" : {
374 | "kind" : "SCALAR",
375 | "name" : "ID",
376 | "ofType" : null
377 | },
378 | "defaultValue" : null
379 | }, {
380 | "name" : "ge",
381 | "description" : null,
382 | "type" : {
383 | "kind" : "SCALAR",
384 | "name" : "ID",
385 | "ofType" : null
386 | },
387 | "defaultValue" : null
388 | }, {
389 | "name" : "gt",
390 | "description" : null,
391 | "type" : {
392 | "kind" : "SCALAR",
393 | "name" : "ID",
394 | "ofType" : null
395 | },
396 | "defaultValue" : null
397 | }, {
398 | "name" : "contains",
399 | "description" : null,
400 | "type" : {
401 | "kind" : "SCALAR",
402 | "name" : "ID",
403 | "ofType" : null
404 | },
405 | "defaultValue" : null
406 | }, {
407 | "name" : "notContains",
408 | "description" : null,
409 | "type" : {
410 | "kind" : "SCALAR",
411 | "name" : "ID",
412 | "ofType" : null
413 | },
414 | "defaultValue" : null
415 | }, {
416 | "name" : "between",
417 | "description" : null,
418 | "type" : {
419 | "kind" : "LIST",
420 | "name" : null,
421 | "ofType" : {
422 | "kind" : "SCALAR",
423 | "name" : "ID",
424 | "ofType" : null
425 | }
426 | },
427 | "defaultValue" : null
428 | }, {
429 | "name" : "beginsWith",
430 | "description" : null,
431 | "type" : {
432 | "kind" : "SCALAR",
433 | "name" : "ID",
434 | "ofType" : null
435 | },
436 | "defaultValue" : null
437 | } ],
438 | "interfaces" : null,
439 | "enumValues" : null,
440 | "possibleTypes" : null
441 | }, {
442 | "kind" : "INPUT_OBJECT",
443 | "name" : "ModelStringFilterInput",
444 | "description" : null,
445 | "fields" : null,
446 | "inputFields" : [ {
447 | "name" : "ne",
448 | "description" : null,
449 | "type" : {
450 | "kind" : "SCALAR",
451 | "name" : "String",
452 | "ofType" : null
453 | },
454 | "defaultValue" : null
455 | }, {
456 | "name" : "eq",
457 | "description" : null,
458 | "type" : {
459 | "kind" : "SCALAR",
460 | "name" : "String",
461 | "ofType" : null
462 | },
463 | "defaultValue" : null
464 | }, {
465 | "name" : "le",
466 | "description" : null,
467 | "type" : {
468 | "kind" : "SCALAR",
469 | "name" : "String",
470 | "ofType" : null
471 | },
472 | "defaultValue" : null
473 | }, {
474 | "name" : "lt",
475 | "description" : null,
476 | "type" : {
477 | "kind" : "SCALAR",
478 | "name" : "String",
479 | "ofType" : null
480 | },
481 | "defaultValue" : null
482 | }, {
483 | "name" : "ge",
484 | "description" : null,
485 | "type" : {
486 | "kind" : "SCALAR",
487 | "name" : "String",
488 | "ofType" : null
489 | },
490 | "defaultValue" : null
491 | }, {
492 | "name" : "gt",
493 | "description" : null,
494 | "type" : {
495 | "kind" : "SCALAR",
496 | "name" : "String",
497 | "ofType" : null
498 | },
499 | "defaultValue" : null
500 | }, {
501 | "name" : "contains",
502 | "description" : null,
503 | "type" : {
504 | "kind" : "SCALAR",
505 | "name" : "String",
506 | "ofType" : null
507 | },
508 | "defaultValue" : null
509 | }, {
510 | "name" : "notContains",
511 | "description" : null,
512 | "type" : {
513 | "kind" : "SCALAR",
514 | "name" : "String",
515 | "ofType" : null
516 | },
517 | "defaultValue" : null
518 | }, {
519 | "name" : "between",
520 | "description" : null,
521 | "type" : {
522 | "kind" : "LIST",
523 | "name" : null,
524 | "ofType" : {
525 | "kind" : "SCALAR",
526 | "name" : "String",
527 | "ofType" : null
528 | }
529 | },
530 | "defaultValue" : null
531 | }, {
532 | "name" : "beginsWith",
533 | "description" : null,
534 | "type" : {
535 | "kind" : "SCALAR",
536 | "name" : "String",
537 | "ofType" : null
538 | },
539 | "defaultValue" : null
540 | } ],
541 | "interfaces" : null,
542 | "enumValues" : null,
543 | "possibleTypes" : null
544 | }, {
545 | "kind" : "INPUT_OBJECT",
546 | "name" : "ModelVisibilityFilterInput",
547 | "description" : null,
548 | "fields" : null,
549 | "inputFields" : [ {
550 | "name" : "eq",
551 | "description" : null,
552 | "type" : {
553 | "kind" : "ENUM",
554 | "name" : "Visibility",
555 | "ofType" : null
556 | },
557 | "defaultValue" : null
558 | }, {
559 | "name" : "ne",
560 | "description" : null,
561 | "type" : {
562 | "kind" : "ENUM",
563 | "name" : "Visibility",
564 | "ofType" : null
565 | },
566 | "defaultValue" : null
567 | } ],
568 | "interfaces" : null,
569 | "enumValues" : null,
570 | "possibleTypes" : null
571 | }, {
572 | "kind" : "SCALAR",
573 | "name" : "Int",
574 | "description" : "Built-in Int",
575 | "fields" : null,
576 | "inputFields" : null,
577 | "interfaces" : null,
578 | "enumValues" : null,
579 | "possibleTypes" : null
580 | }, {
581 | "kind" : "OBJECT",
582 | "name" : "Mutation",
583 | "description" : null,
584 | "fields" : [ {
585 | "name" : "createUser",
586 | "description" : null,
587 | "args" : [ {
588 | "name" : "input",
589 | "description" : null,
590 | "type" : {
591 | "kind" : "NON_NULL",
592 | "name" : null,
593 | "ofType" : {
594 | "kind" : "INPUT_OBJECT",
595 | "name" : "CreateUserInput",
596 | "ofType" : null
597 | }
598 | },
599 | "defaultValue" : null
600 | } ],
601 | "type" : {
602 | "kind" : "OBJECT",
603 | "name" : "User",
604 | "ofType" : null
605 | },
606 | "isDeprecated" : false,
607 | "deprecationReason" : null
608 | }, {
609 | "name" : "updateUser",
610 | "description" : null,
611 | "args" : [ {
612 | "name" : "input",
613 | "description" : null,
614 | "type" : {
615 | "kind" : "NON_NULL",
616 | "name" : null,
617 | "ofType" : {
618 | "kind" : "INPUT_OBJECT",
619 | "name" : "UpdateUserInput",
620 | "ofType" : null
621 | }
622 | },
623 | "defaultValue" : null
624 | } ],
625 | "type" : {
626 | "kind" : "OBJECT",
627 | "name" : "User",
628 | "ofType" : null
629 | },
630 | "isDeprecated" : false,
631 | "deprecationReason" : null
632 | }, {
633 | "name" : "deleteUser",
634 | "description" : null,
635 | "args" : [ {
636 | "name" : "input",
637 | "description" : null,
638 | "type" : {
639 | "kind" : "NON_NULL",
640 | "name" : null,
641 | "ofType" : {
642 | "kind" : "INPUT_OBJECT",
643 | "name" : "DeleteUserInput",
644 | "ofType" : null
645 | }
646 | },
647 | "defaultValue" : null
648 | } ],
649 | "type" : {
650 | "kind" : "OBJECT",
651 | "name" : "User",
652 | "ofType" : null
653 | },
654 | "isDeprecated" : false,
655 | "deprecationReason" : null
656 | } ],
657 | "inputFields" : null,
658 | "interfaces" : [ ],
659 | "enumValues" : null,
660 | "possibleTypes" : null
661 | }, {
662 | "kind" : "INPUT_OBJECT",
663 | "name" : "CreateUserInput",
664 | "description" : null,
665 | "fields" : null,
666 | "inputFields" : [ {
667 | "name" : "id",
668 | "description" : null,
669 | "type" : {
670 | "kind" : "SCALAR",
671 | "name" : "ID",
672 | "ofType" : null
673 | },
674 | "defaultValue" : null
675 | }, {
676 | "name" : "username",
677 | "description" : null,
678 | "type" : {
679 | "kind" : "SCALAR",
680 | "name" : "String",
681 | "ofType" : null
682 | },
683 | "defaultValue" : null
684 | }, {
685 | "name" : "visibility",
686 | "description" : null,
687 | "type" : {
688 | "kind" : "ENUM",
689 | "name" : "Visibility",
690 | "ofType" : null
691 | },
692 | "defaultValue" : null
693 | }, {
694 | "name" : "avatar",
695 | "description" : null,
696 | "type" : {
697 | "kind" : "INPUT_OBJECT",
698 | "name" : "S3ObjectInput",
699 | "ofType" : null
700 | },
701 | "defaultValue" : null
702 | } ],
703 | "interfaces" : null,
704 | "enumValues" : null,
705 | "possibleTypes" : null
706 | }, {
707 | "kind" : "INPUT_OBJECT",
708 | "name" : "S3ObjectInput",
709 | "description" : null,
710 | "fields" : null,
711 | "inputFields" : [ {
712 | "name" : "bucket",
713 | "description" : null,
714 | "type" : {
715 | "kind" : "NON_NULL",
716 | "name" : null,
717 | "ofType" : {
718 | "kind" : "SCALAR",
719 | "name" : "String",
720 | "ofType" : null
721 | }
722 | },
723 | "defaultValue" : null
724 | }, {
725 | "name" : "region",
726 | "description" : null,
727 | "type" : {
728 | "kind" : "NON_NULL",
729 | "name" : null,
730 | "ofType" : {
731 | "kind" : "SCALAR",
732 | "name" : "String",
733 | "ofType" : null
734 | }
735 | },
736 | "defaultValue" : null
737 | }, {
738 | "name" : "key",
739 | "description" : null,
740 | "type" : {
741 | "kind" : "NON_NULL",
742 | "name" : null,
743 | "ofType" : {
744 | "kind" : "SCALAR",
745 | "name" : "String",
746 | "ofType" : null
747 | }
748 | },
749 | "defaultValue" : null
750 | } ],
751 | "interfaces" : null,
752 | "enumValues" : null,
753 | "possibleTypes" : null
754 | }, {
755 | "kind" : "INPUT_OBJECT",
756 | "name" : "UpdateUserInput",
757 | "description" : null,
758 | "fields" : null,
759 | "inputFields" : [ {
760 | "name" : "id",
761 | "description" : null,
762 | "type" : {
763 | "kind" : "NON_NULL",
764 | "name" : null,
765 | "ofType" : {
766 | "kind" : "SCALAR",
767 | "name" : "ID",
768 | "ofType" : null
769 | }
770 | },
771 | "defaultValue" : null
772 | }, {
773 | "name" : "username",
774 | "description" : null,
775 | "type" : {
776 | "kind" : "SCALAR",
777 | "name" : "String",
778 | "ofType" : null
779 | },
780 | "defaultValue" : null
781 | }, {
782 | "name" : "visibility",
783 | "description" : null,
784 | "type" : {
785 | "kind" : "ENUM",
786 | "name" : "Visibility",
787 | "ofType" : null
788 | },
789 | "defaultValue" : null
790 | }, {
791 | "name" : "avatar",
792 | "description" : null,
793 | "type" : {
794 | "kind" : "INPUT_OBJECT",
795 | "name" : "S3ObjectInput",
796 | "ofType" : null
797 | },
798 | "defaultValue" : null
799 | } ],
800 | "interfaces" : null,
801 | "enumValues" : null,
802 | "possibleTypes" : null
803 | }, {
804 | "kind" : "INPUT_OBJECT",
805 | "name" : "DeleteUserInput",
806 | "description" : null,
807 | "fields" : null,
808 | "inputFields" : [ {
809 | "name" : "id",
810 | "description" : null,
811 | "type" : {
812 | "kind" : "SCALAR",
813 | "name" : "ID",
814 | "ofType" : null
815 | },
816 | "defaultValue" : null
817 | } ],
818 | "interfaces" : null,
819 | "enumValues" : null,
820 | "possibleTypes" : null
821 | }, {
822 | "kind" : "OBJECT",
823 | "name" : "Subscription",
824 | "description" : null,
825 | "fields" : [ {
826 | "name" : "onCreateUser",
827 | "description" : null,
828 | "args" : [ ],
829 | "type" : {
830 | "kind" : "OBJECT",
831 | "name" : "User",
832 | "ofType" : null
833 | },
834 | "isDeprecated" : false,
835 | "deprecationReason" : null
836 | }, {
837 | "name" : "onUpdateUser",
838 | "description" : null,
839 | "args" : [ ],
840 | "type" : {
841 | "kind" : "OBJECT",
842 | "name" : "User",
843 | "ofType" : null
844 | },
845 | "isDeprecated" : false,
846 | "deprecationReason" : null
847 | }, {
848 | "name" : "onDeleteUser",
849 | "description" : null,
850 | "args" : [ ],
851 | "type" : {
852 | "kind" : "OBJECT",
853 | "name" : "User",
854 | "ofType" : null
855 | },
856 | "isDeprecated" : false,
857 | "deprecationReason" : null
858 | } ],
859 | "inputFields" : null,
860 | "interfaces" : [ ],
861 | "enumValues" : null,
862 | "possibleTypes" : null
863 | }, {
864 | "kind" : "ENUM",
865 | "name" : "ModelSortDirection",
866 | "description" : null,
867 | "fields" : null,
868 | "inputFields" : null,
869 | "interfaces" : null,
870 | "enumValues" : [ {
871 | "name" : "ASC",
872 | "description" : null,
873 | "isDeprecated" : false,
874 | "deprecationReason" : null
875 | }, {
876 | "name" : "DESC",
877 | "description" : null,
878 | "isDeprecated" : false,
879 | "deprecationReason" : null
880 | } ],
881 | "possibleTypes" : null
882 | }, {
883 | "kind" : "INPUT_OBJECT",
884 | "name" : "ModelBooleanFilterInput",
885 | "description" : null,
886 | "fields" : null,
887 | "inputFields" : [ {
888 | "name" : "ne",
889 | "description" : null,
890 | "type" : {
891 | "kind" : "SCALAR",
892 | "name" : "Boolean",
893 | "ofType" : null
894 | },
895 | "defaultValue" : null
896 | }, {
897 | "name" : "eq",
898 | "description" : null,
899 | "type" : {
900 | "kind" : "SCALAR",
901 | "name" : "Boolean",
902 | "ofType" : null
903 | },
904 | "defaultValue" : null
905 | } ],
906 | "interfaces" : null,
907 | "enumValues" : null,
908 | "possibleTypes" : null
909 | }, {
910 | "kind" : "SCALAR",
911 | "name" : "Boolean",
912 | "description" : "Built-in Boolean",
913 | "fields" : null,
914 | "inputFields" : null,
915 | "interfaces" : null,
916 | "enumValues" : null,
917 | "possibleTypes" : null
918 | }, {
919 | "kind" : "INPUT_OBJECT",
920 | "name" : "ModelFloatFilterInput",
921 | "description" : null,
922 | "fields" : null,
923 | "inputFields" : [ {
924 | "name" : "ne",
925 | "description" : null,
926 | "type" : {
927 | "kind" : "SCALAR",
928 | "name" : "Float",
929 | "ofType" : null
930 | },
931 | "defaultValue" : null
932 | }, {
933 | "name" : "eq",
934 | "description" : null,
935 | "type" : {
936 | "kind" : "SCALAR",
937 | "name" : "Float",
938 | "ofType" : null
939 | },
940 | "defaultValue" : null
941 | }, {
942 | "name" : "le",
943 | "description" : null,
944 | "type" : {
945 | "kind" : "SCALAR",
946 | "name" : "Float",
947 | "ofType" : null
948 | },
949 | "defaultValue" : null
950 | }, {
951 | "name" : "lt",
952 | "description" : null,
953 | "type" : {
954 | "kind" : "SCALAR",
955 | "name" : "Float",
956 | "ofType" : null
957 | },
958 | "defaultValue" : null
959 | }, {
960 | "name" : "ge",
961 | "description" : null,
962 | "type" : {
963 | "kind" : "SCALAR",
964 | "name" : "Float",
965 | "ofType" : null
966 | },
967 | "defaultValue" : null
968 | }, {
969 | "name" : "gt",
970 | "description" : null,
971 | "type" : {
972 | "kind" : "SCALAR",
973 | "name" : "Float",
974 | "ofType" : null
975 | },
976 | "defaultValue" : null
977 | }, {
978 | "name" : "contains",
979 | "description" : null,
980 | "type" : {
981 | "kind" : "SCALAR",
982 | "name" : "Float",
983 | "ofType" : null
984 | },
985 | "defaultValue" : null
986 | }, {
987 | "name" : "notContains",
988 | "description" : null,
989 | "type" : {
990 | "kind" : "SCALAR",
991 | "name" : "Float",
992 | "ofType" : null
993 | },
994 | "defaultValue" : null
995 | }, {
996 | "name" : "between",
997 | "description" : null,
998 | "type" : {
999 | "kind" : "LIST",
1000 | "name" : null,
1001 | "ofType" : {
1002 | "kind" : "SCALAR",
1003 | "name" : "Float",
1004 | "ofType" : null
1005 | }
1006 | },
1007 | "defaultValue" : null
1008 | } ],
1009 | "interfaces" : null,
1010 | "enumValues" : null,
1011 | "possibleTypes" : null
1012 | }, {
1013 | "kind" : "SCALAR",
1014 | "name" : "Float",
1015 | "description" : "Built-in Float",
1016 | "fields" : null,
1017 | "inputFields" : null,
1018 | "interfaces" : null,
1019 | "enumValues" : null,
1020 | "possibleTypes" : null
1021 | }, {
1022 | "kind" : "INPUT_OBJECT",
1023 | "name" : "ModelIntFilterInput",
1024 | "description" : null,
1025 | "fields" : null,
1026 | "inputFields" : [ {
1027 | "name" : "ne",
1028 | "description" : null,
1029 | "type" : {
1030 | "kind" : "SCALAR",
1031 | "name" : "Int",
1032 | "ofType" : null
1033 | },
1034 | "defaultValue" : null
1035 | }, {
1036 | "name" : "eq",
1037 | "description" : null,
1038 | "type" : {
1039 | "kind" : "SCALAR",
1040 | "name" : "Int",
1041 | "ofType" : null
1042 | },
1043 | "defaultValue" : null
1044 | }, {
1045 | "name" : "le",
1046 | "description" : null,
1047 | "type" : {
1048 | "kind" : "SCALAR",
1049 | "name" : "Int",
1050 | "ofType" : null
1051 | },
1052 | "defaultValue" : null
1053 | }, {
1054 | "name" : "lt",
1055 | "description" : null,
1056 | "type" : {
1057 | "kind" : "SCALAR",
1058 | "name" : "Int",
1059 | "ofType" : null
1060 | },
1061 | "defaultValue" : null
1062 | }, {
1063 | "name" : "ge",
1064 | "description" : null,
1065 | "type" : {
1066 | "kind" : "SCALAR",
1067 | "name" : "Int",
1068 | "ofType" : null
1069 | },
1070 | "defaultValue" : null
1071 | }, {
1072 | "name" : "gt",
1073 | "description" : null,
1074 | "type" : {
1075 | "kind" : "SCALAR",
1076 | "name" : "Int",
1077 | "ofType" : null
1078 | },
1079 | "defaultValue" : null
1080 | }, {
1081 | "name" : "contains",
1082 | "description" : null,
1083 | "type" : {
1084 | "kind" : "SCALAR",
1085 | "name" : "Int",
1086 | "ofType" : null
1087 | },
1088 | "defaultValue" : null
1089 | }, {
1090 | "name" : "notContains",
1091 | "description" : null,
1092 | "type" : {
1093 | "kind" : "SCALAR",
1094 | "name" : "Int",
1095 | "ofType" : null
1096 | },
1097 | "defaultValue" : null
1098 | }, {
1099 | "name" : "between",
1100 | "description" : null,
1101 | "type" : {
1102 | "kind" : "LIST",
1103 | "name" : null,
1104 | "ofType" : {
1105 | "kind" : "SCALAR",
1106 | "name" : "Int",
1107 | "ofType" : null
1108 | }
1109 | },
1110 | "defaultValue" : null
1111 | } ],
1112 | "interfaces" : null,
1113 | "enumValues" : null,
1114 | "possibleTypes" : null
1115 | }, {
1116 | "kind" : "OBJECT",
1117 | "name" : "__Schema",
1118 | "description" : "A GraphQL Introspection defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, the entry points for query, mutation, and subscription operations.",
1119 | "fields" : [ {
1120 | "name" : "types",
1121 | "description" : "A list of all types supported by this server.",
1122 | "args" : [ ],
1123 | "type" : {
1124 | "kind" : "NON_NULL",
1125 | "name" : null,
1126 | "ofType" : {
1127 | "kind" : "LIST",
1128 | "name" : null,
1129 | "ofType" : {
1130 | "kind" : "NON_NULL",
1131 | "name" : null,
1132 | "ofType" : {
1133 | "kind" : "OBJECT",
1134 | "name" : "__Type",
1135 | "ofType" : null
1136 | }
1137 | }
1138 | }
1139 | },
1140 | "isDeprecated" : false,
1141 | "deprecationReason" : null
1142 | }, {
1143 | "name" : "queryType",
1144 | "description" : "The type that query operations will be rooted at.",
1145 | "args" : [ ],
1146 | "type" : {
1147 | "kind" : "NON_NULL",
1148 | "name" : null,
1149 | "ofType" : {
1150 | "kind" : "OBJECT",
1151 | "name" : "__Type",
1152 | "ofType" : null
1153 | }
1154 | },
1155 | "isDeprecated" : false,
1156 | "deprecationReason" : null
1157 | }, {
1158 | "name" : "mutationType",
1159 | "description" : "If this server supports mutation, the type that mutation operations will be rooted at.",
1160 | "args" : [ ],
1161 | "type" : {
1162 | "kind" : "OBJECT",
1163 | "name" : "__Type",
1164 | "ofType" : null
1165 | },
1166 | "isDeprecated" : false,
1167 | "deprecationReason" : null
1168 | }, {
1169 | "name" : "directives",
1170 | "description" : "'A list of all directives supported by this server.",
1171 | "args" : [ ],
1172 | "type" : {
1173 | "kind" : "NON_NULL",
1174 | "name" : null,
1175 | "ofType" : {
1176 | "kind" : "LIST",
1177 | "name" : null,
1178 | "ofType" : {
1179 | "kind" : "NON_NULL",
1180 | "name" : null,
1181 | "ofType" : {
1182 | "kind" : "OBJECT",
1183 | "name" : "__Directive",
1184 | "ofType" : null
1185 | }
1186 | }
1187 | }
1188 | },
1189 | "isDeprecated" : false,
1190 | "deprecationReason" : null
1191 | }, {
1192 | "name" : "subscriptionType",
1193 | "description" : "'If this server support subscription, the type that subscription operations will be rooted at.",
1194 | "args" : [ ],
1195 | "type" : {
1196 | "kind" : "OBJECT",
1197 | "name" : "__Type",
1198 | "ofType" : null
1199 | },
1200 | "isDeprecated" : false,
1201 | "deprecationReason" : null
1202 | } ],
1203 | "inputFields" : null,
1204 | "interfaces" : [ ],
1205 | "enumValues" : null,
1206 | "possibleTypes" : null
1207 | }, {
1208 | "kind" : "OBJECT",
1209 | "name" : "__Type",
1210 | "description" : null,
1211 | "fields" : [ {
1212 | "name" : "kind",
1213 | "description" : null,
1214 | "args" : [ ],
1215 | "type" : {
1216 | "kind" : "NON_NULL",
1217 | "name" : null,
1218 | "ofType" : {
1219 | "kind" : "ENUM",
1220 | "name" : "__TypeKind",
1221 | "ofType" : null
1222 | }
1223 | },
1224 | "isDeprecated" : false,
1225 | "deprecationReason" : null
1226 | }, {
1227 | "name" : "name",
1228 | "description" : null,
1229 | "args" : [ ],
1230 | "type" : {
1231 | "kind" : "SCALAR",
1232 | "name" : "String",
1233 | "ofType" : null
1234 | },
1235 | "isDeprecated" : false,
1236 | "deprecationReason" : null
1237 | }, {
1238 | "name" : "description",
1239 | "description" : null,
1240 | "args" : [ ],
1241 | "type" : {
1242 | "kind" : "SCALAR",
1243 | "name" : "String",
1244 | "ofType" : null
1245 | },
1246 | "isDeprecated" : false,
1247 | "deprecationReason" : null
1248 | }, {
1249 | "name" : "fields",
1250 | "description" : null,
1251 | "args" : [ {
1252 | "name" : "includeDeprecated",
1253 | "description" : null,
1254 | "type" : {
1255 | "kind" : "SCALAR",
1256 | "name" : "Boolean",
1257 | "ofType" : null
1258 | },
1259 | "defaultValue" : "false"
1260 | } ],
1261 | "type" : {
1262 | "kind" : "LIST",
1263 | "name" : null,
1264 | "ofType" : {
1265 | "kind" : "NON_NULL",
1266 | "name" : null,
1267 | "ofType" : {
1268 | "kind" : "OBJECT",
1269 | "name" : "__Field",
1270 | "ofType" : null
1271 | }
1272 | }
1273 | },
1274 | "isDeprecated" : false,
1275 | "deprecationReason" : null
1276 | }, {
1277 | "name" : "interfaces",
1278 | "description" : null,
1279 | "args" : [ ],
1280 | "type" : {
1281 | "kind" : "LIST",
1282 | "name" : null,
1283 | "ofType" : {
1284 | "kind" : "NON_NULL",
1285 | "name" : null,
1286 | "ofType" : {
1287 | "kind" : "OBJECT",
1288 | "name" : "__Type",
1289 | "ofType" : null
1290 | }
1291 | }
1292 | },
1293 | "isDeprecated" : false,
1294 | "deprecationReason" : null
1295 | }, {
1296 | "name" : "possibleTypes",
1297 | "description" : null,
1298 | "args" : [ ],
1299 | "type" : {
1300 | "kind" : "LIST",
1301 | "name" : null,
1302 | "ofType" : {
1303 | "kind" : "NON_NULL",
1304 | "name" : null,
1305 | "ofType" : {
1306 | "kind" : "OBJECT",
1307 | "name" : "__Type",
1308 | "ofType" : null
1309 | }
1310 | }
1311 | },
1312 | "isDeprecated" : false,
1313 | "deprecationReason" : null
1314 | }, {
1315 | "name" : "enumValues",
1316 | "description" : null,
1317 | "args" : [ {
1318 | "name" : "includeDeprecated",
1319 | "description" : null,
1320 | "type" : {
1321 | "kind" : "SCALAR",
1322 | "name" : "Boolean",
1323 | "ofType" : null
1324 | },
1325 | "defaultValue" : "false"
1326 | } ],
1327 | "type" : {
1328 | "kind" : "LIST",
1329 | "name" : null,
1330 | "ofType" : {
1331 | "kind" : "NON_NULL",
1332 | "name" : null,
1333 | "ofType" : {
1334 | "kind" : "OBJECT",
1335 | "name" : "__EnumValue",
1336 | "ofType" : null
1337 | }
1338 | }
1339 | },
1340 | "isDeprecated" : false,
1341 | "deprecationReason" : null
1342 | }, {
1343 | "name" : "inputFields",
1344 | "description" : null,
1345 | "args" : [ ],
1346 | "type" : {
1347 | "kind" : "LIST",
1348 | "name" : null,
1349 | "ofType" : {
1350 | "kind" : "NON_NULL",
1351 | "name" : null,
1352 | "ofType" : {
1353 | "kind" : "OBJECT",
1354 | "name" : "__InputValue",
1355 | "ofType" : null
1356 | }
1357 | }
1358 | },
1359 | "isDeprecated" : false,
1360 | "deprecationReason" : null
1361 | }, {
1362 | "name" : "ofType",
1363 | "description" : null,
1364 | "args" : [ ],
1365 | "type" : {
1366 | "kind" : "OBJECT",
1367 | "name" : "__Type",
1368 | "ofType" : null
1369 | },
1370 | "isDeprecated" : false,
1371 | "deprecationReason" : null
1372 | } ],
1373 | "inputFields" : null,
1374 | "interfaces" : [ ],
1375 | "enumValues" : null,
1376 | "possibleTypes" : null
1377 | }, {
1378 | "kind" : "ENUM",
1379 | "name" : "__TypeKind",
1380 | "description" : "An enum describing what kind of type a given __Type is",
1381 | "fields" : null,
1382 | "inputFields" : null,
1383 | "interfaces" : null,
1384 | "enumValues" : [ {
1385 | "name" : "SCALAR",
1386 | "description" : "Indicates this type is a scalar.",
1387 | "isDeprecated" : false,
1388 | "deprecationReason" : null
1389 | }, {
1390 | "name" : "OBJECT",
1391 | "description" : "Indicates this type is an object. `fields` and `interfaces` are valid fields.",
1392 | "isDeprecated" : false,
1393 | "deprecationReason" : null
1394 | }, {
1395 | "name" : "INTERFACE",
1396 | "description" : "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.",
1397 | "isDeprecated" : false,
1398 | "deprecationReason" : null
1399 | }, {
1400 | "name" : "UNION",
1401 | "description" : "Indicates this type is a union. `possibleTypes` is a valid field.",
1402 | "isDeprecated" : false,
1403 | "deprecationReason" : null
1404 | }, {
1405 | "name" : "ENUM",
1406 | "description" : "Indicates this type is an enum. `enumValues` is a valid field.",
1407 | "isDeprecated" : false,
1408 | "deprecationReason" : null
1409 | }, {
1410 | "name" : "INPUT_OBJECT",
1411 | "description" : "Indicates this type is an input object. `inputFields` is a valid field.",
1412 | "isDeprecated" : false,
1413 | "deprecationReason" : null
1414 | }, {
1415 | "name" : "LIST",
1416 | "description" : "Indicates this type is a list. `ofType` is a valid field.",
1417 | "isDeprecated" : false,
1418 | "deprecationReason" : null
1419 | }, {
1420 | "name" : "NON_NULL",
1421 | "description" : "Indicates this type is a non-null. `ofType` is a valid field.",
1422 | "isDeprecated" : false,
1423 | "deprecationReason" : null
1424 | } ],
1425 | "possibleTypes" : null
1426 | }, {
1427 | "kind" : "OBJECT",
1428 | "name" : "__Field",
1429 | "description" : null,
1430 | "fields" : [ {
1431 | "name" : "name",
1432 | "description" : null,
1433 | "args" : [ ],
1434 | "type" : {
1435 | "kind" : "NON_NULL",
1436 | "name" : null,
1437 | "ofType" : {
1438 | "kind" : "SCALAR",
1439 | "name" : "String",
1440 | "ofType" : null
1441 | }
1442 | },
1443 | "isDeprecated" : false,
1444 | "deprecationReason" : null
1445 | }, {
1446 | "name" : "description",
1447 | "description" : null,
1448 | "args" : [ ],
1449 | "type" : {
1450 | "kind" : "SCALAR",
1451 | "name" : "String",
1452 | "ofType" : null
1453 | },
1454 | "isDeprecated" : false,
1455 | "deprecationReason" : null
1456 | }, {
1457 | "name" : "args",
1458 | "description" : null,
1459 | "args" : [ ],
1460 | "type" : {
1461 | "kind" : "NON_NULL",
1462 | "name" : null,
1463 | "ofType" : {
1464 | "kind" : "LIST",
1465 | "name" : null,
1466 | "ofType" : {
1467 | "kind" : "NON_NULL",
1468 | "name" : null,
1469 | "ofType" : {
1470 | "kind" : "OBJECT",
1471 | "name" : "__InputValue",
1472 | "ofType" : null
1473 | }
1474 | }
1475 | }
1476 | },
1477 | "isDeprecated" : false,
1478 | "deprecationReason" : null
1479 | }, {
1480 | "name" : "type",
1481 | "description" : null,
1482 | "args" : [ ],
1483 | "type" : {
1484 | "kind" : "NON_NULL",
1485 | "name" : null,
1486 | "ofType" : {
1487 | "kind" : "OBJECT",
1488 | "name" : "__Type",
1489 | "ofType" : null
1490 | }
1491 | },
1492 | "isDeprecated" : false,
1493 | "deprecationReason" : null
1494 | }, {
1495 | "name" : "isDeprecated",
1496 | "description" : null,
1497 | "args" : [ ],
1498 | "type" : {
1499 | "kind" : "NON_NULL",
1500 | "name" : null,
1501 | "ofType" : {
1502 | "kind" : "SCALAR",
1503 | "name" : "Boolean",
1504 | "ofType" : null
1505 | }
1506 | },
1507 | "isDeprecated" : false,
1508 | "deprecationReason" : null
1509 | }, {
1510 | "name" : "deprecationReason",
1511 | "description" : null,
1512 | "args" : [ ],
1513 | "type" : {
1514 | "kind" : "SCALAR",
1515 | "name" : "String",
1516 | "ofType" : null
1517 | },
1518 | "isDeprecated" : false,
1519 | "deprecationReason" : null
1520 | } ],
1521 | "inputFields" : null,
1522 | "interfaces" : [ ],
1523 | "enumValues" : null,
1524 | "possibleTypes" : null
1525 | }, {
1526 | "kind" : "OBJECT",
1527 | "name" : "__InputValue",
1528 | "description" : null,
1529 | "fields" : [ {
1530 | "name" : "name",
1531 | "description" : null,
1532 | "args" : [ ],
1533 | "type" : {
1534 | "kind" : "NON_NULL",
1535 | "name" : null,
1536 | "ofType" : {
1537 | "kind" : "SCALAR",
1538 | "name" : "String",
1539 | "ofType" : null
1540 | }
1541 | },
1542 | "isDeprecated" : false,
1543 | "deprecationReason" : null
1544 | }, {
1545 | "name" : "description",
1546 | "description" : null,
1547 | "args" : [ ],
1548 | "type" : {
1549 | "kind" : "SCALAR",
1550 | "name" : "String",
1551 | "ofType" : null
1552 | },
1553 | "isDeprecated" : false,
1554 | "deprecationReason" : null
1555 | }, {
1556 | "name" : "type",
1557 | "description" : null,
1558 | "args" : [ ],
1559 | "type" : {
1560 | "kind" : "NON_NULL",
1561 | "name" : null,
1562 | "ofType" : {
1563 | "kind" : "OBJECT",
1564 | "name" : "__Type",
1565 | "ofType" : null
1566 | }
1567 | },
1568 | "isDeprecated" : false,
1569 | "deprecationReason" : null
1570 | }, {
1571 | "name" : "defaultValue",
1572 | "description" : null,
1573 | "args" : [ ],
1574 | "type" : {
1575 | "kind" : "SCALAR",
1576 | "name" : "String",
1577 | "ofType" : null
1578 | },
1579 | "isDeprecated" : false,
1580 | "deprecationReason" : null
1581 | } ],
1582 | "inputFields" : null,
1583 | "interfaces" : [ ],
1584 | "enumValues" : null,
1585 | "possibleTypes" : null
1586 | }, {
1587 | "kind" : "OBJECT",
1588 | "name" : "__EnumValue",
1589 | "description" : null,
1590 | "fields" : [ {
1591 | "name" : "name",
1592 | "description" : null,
1593 | "args" : [ ],
1594 | "type" : {
1595 | "kind" : "NON_NULL",
1596 | "name" : null,
1597 | "ofType" : {
1598 | "kind" : "SCALAR",
1599 | "name" : "String",
1600 | "ofType" : null
1601 | }
1602 | },
1603 | "isDeprecated" : false,
1604 | "deprecationReason" : null
1605 | }, {
1606 | "name" : "description",
1607 | "description" : null,
1608 | "args" : [ ],
1609 | "type" : {
1610 | "kind" : "SCALAR",
1611 | "name" : "String",
1612 | "ofType" : null
1613 | },
1614 | "isDeprecated" : false,
1615 | "deprecationReason" : null
1616 | }, {
1617 | "name" : "isDeprecated",
1618 | "description" : null,
1619 | "args" : [ ],
1620 | "type" : {
1621 | "kind" : "NON_NULL",
1622 | "name" : null,
1623 | "ofType" : {
1624 | "kind" : "SCALAR",
1625 | "name" : "Boolean",
1626 | "ofType" : null
1627 | }
1628 | },
1629 | "isDeprecated" : false,
1630 | "deprecationReason" : null
1631 | }, {
1632 | "name" : "deprecationReason",
1633 | "description" : null,
1634 | "args" : [ ],
1635 | "type" : {
1636 | "kind" : "SCALAR",
1637 | "name" : "String",
1638 | "ofType" : null
1639 | },
1640 | "isDeprecated" : false,
1641 | "deprecationReason" : null
1642 | } ],
1643 | "inputFields" : null,
1644 | "interfaces" : [ ],
1645 | "enumValues" : null,
1646 | "possibleTypes" : null
1647 | }, {
1648 | "kind" : "OBJECT",
1649 | "name" : "__Directive",
1650 | "description" : null,
1651 | "fields" : [ {
1652 | "name" : "name",
1653 | "description" : null,
1654 | "args" : [ ],
1655 | "type" : {
1656 | "kind" : "SCALAR",
1657 | "name" : "String",
1658 | "ofType" : null
1659 | },
1660 | "isDeprecated" : false,
1661 | "deprecationReason" : null
1662 | }, {
1663 | "name" : "description",
1664 | "description" : null,
1665 | "args" : [ ],
1666 | "type" : {
1667 | "kind" : "SCALAR",
1668 | "name" : "String",
1669 | "ofType" : null
1670 | },
1671 | "isDeprecated" : false,
1672 | "deprecationReason" : null
1673 | }, {
1674 | "name" : "locations",
1675 | "description" : null,
1676 | "args" : [ ],
1677 | "type" : {
1678 | "kind" : "LIST",
1679 | "name" : null,
1680 | "ofType" : {
1681 | "kind" : "NON_NULL",
1682 | "name" : null,
1683 | "ofType" : {
1684 | "kind" : "ENUM",
1685 | "name" : "__DirectiveLocation",
1686 | "ofType" : null
1687 | }
1688 | }
1689 | },
1690 | "isDeprecated" : false,
1691 | "deprecationReason" : null
1692 | }, {
1693 | "name" : "args",
1694 | "description" : null,
1695 | "args" : [ ],
1696 | "type" : {
1697 | "kind" : "NON_NULL",
1698 | "name" : null,
1699 | "ofType" : {
1700 | "kind" : "LIST",
1701 | "name" : null,
1702 | "ofType" : {
1703 | "kind" : "NON_NULL",
1704 | "name" : null,
1705 | "ofType" : {
1706 | "kind" : "OBJECT",
1707 | "name" : "__InputValue",
1708 | "ofType" : null
1709 | }
1710 | }
1711 | }
1712 | },
1713 | "isDeprecated" : false,
1714 | "deprecationReason" : null
1715 | }, {
1716 | "name" : "onOperation",
1717 | "description" : null,
1718 | "args" : [ ],
1719 | "type" : {
1720 | "kind" : "SCALAR",
1721 | "name" : "Boolean",
1722 | "ofType" : null
1723 | },
1724 | "isDeprecated" : true,
1725 | "deprecationReason" : "Use `locations`."
1726 | }, {
1727 | "name" : "onFragment",
1728 | "description" : null,
1729 | "args" : [ ],
1730 | "type" : {
1731 | "kind" : "SCALAR",
1732 | "name" : "Boolean",
1733 | "ofType" : null
1734 | },
1735 | "isDeprecated" : true,
1736 | "deprecationReason" : "Use `locations`."
1737 | }, {
1738 | "name" : "onField",
1739 | "description" : null,
1740 | "args" : [ ],
1741 | "type" : {
1742 | "kind" : "SCALAR",
1743 | "name" : "Boolean",
1744 | "ofType" : null
1745 | },
1746 | "isDeprecated" : true,
1747 | "deprecationReason" : "Use `locations`."
1748 | } ],
1749 | "inputFields" : null,
1750 | "interfaces" : [ ],
1751 | "enumValues" : null,
1752 | "possibleTypes" : null
1753 | }, {
1754 | "kind" : "ENUM",
1755 | "name" : "__DirectiveLocation",
1756 | "description" : "An enum describing valid locations where a directive can be placed",
1757 | "fields" : null,
1758 | "inputFields" : null,
1759 | "interfaces" : null,
1760 | "enumValues" : [ {
1761 | "name" : "QUERY",
1762 | "description" : "Indicates the directive is valid on queries.",
1763 | "isDeprecated" : false,
1764 | "deprecationReason" : null
1765 | }, {
1766 | "name" : "MUTATION",
1767 | "description" : "Indicates the directive is valid on mutations.",
1768 | "isDeprecated" : false,
1769 | "deprecationReason" : null
1770 | }, {
1771 | "name" : "FIELD",
1772 | "description" : "Indicates the directive is valid on fields.",
1773 | "isDeprecated" : false,
1774 | "deprecationReason" : null
1775 | }, {
1776 | "name" : "FRAGMENT_DEFINITION",
1777 | "description" : "Indicates the directive is valid on fragment definitions.",
1778 | "isDeprecated" : false,
1779 | "deprecationReason" : null
1780 | }, {
1781 | "name" : "FRAGMENT_SPREAD",
1782 | "description" : "Indicates the directive is valid on fragment spreads.",
1783 | "isDeprecated" : false,
1784 | "deprecationReason" : null
1785 | }, {
1786 | "name" : "INLINE_FRAGMENT",
1787 | "description" : "Indicates the directive is valid on inline fragments.",
1788 | "isDeprecated" : false,
1789 | "deprecationReason" : null
1790 | }, {
1791 | "name" : "SCHEMA",
1792 | "description" : "Indicates the directive is valid on a schema SDL definition.",
1793 | "isDeprecated" : false,
1794 | "deprecationReason" : null
1795 | }, {
1796 | "name" : "SCALAR",
1797 | "description" : "Indicates the directive is valid on a scalar SDL definition.",
1798 | "isDeprecated" : false,
1799 | "deprecationReason" : null
1800 | }, {
1801 | "name" : "OBJECT",
1802 | "description" : "Indicates the directive is valid on an object SDL definition.",
1803 | "isDeprecated" : false,
1804 | "deprecationReason" : null
1805 | }, {
1806 | "name" : "FIELD_DEFINITION",
1807 | "description" : "Indicates the directive is valid on a field SDL definition.",
1808 | "isDeprecated" : false,
1809 | "deprecationReason" : null
1810 | }, {
1811 | "name" : "ARGUMENT_DEFINITION",
1812 | "description" : "Indicates the directive is valid on a field argument SDL definition.",
1813 | "isDeprecated" : false,
1814 | "deprecationReason" : null
1815 | }, {
1816 | "name" : "INTERFACE",
1817 | "description" : "Indicates the directive is valid on an interface SDL definition.",
1818 | "isDeprecated" : false,
1819 | "deprecationReason" : null
1820 | }, {
1821 | "name" : "UNION",
1822 | "description" : "Indicates the directive is valid on an union SDL definition.",
1823 | "isDeprecated" : false,
1824 | "deprecationReason" : null
1825 | }, {
1826 | "name" : "ENUM",
1827 | "description" : "Indicates the directive is valid on an enum SDL definition.",
1828 | "isDeprecated" : false,
1829 | "deprecationReason" : null
1830 | }, {
1831 | "name" : "ENUM_VALUE",
1832 | "description" : "Indicates the directive is valid on an enum value SDL definition.",
1833 | "isDeprecated" : false,
1834 | "deprecationReason" : null
1835 | }, {
1836 | "name" : "INPUT_OBJECT",
1837 | "description" : "Indicates the directive is valid on an input object SDL definition.",
1838 | "isDeprecated" : false,
1839 | "deprecationReason" : null
1840 | }, {
1841 | "name" : "INPUT_FIELD_DEFINITION",
1842 | "description" : "Indicates the directive is valid on an input object field SDL definition.",
1843 | "isDeprecated" : false,
1844 | "deprecationReason" : null
1845 | } ],
1846 | "possibleTypes" : null
1847 | } ],
1848 | "directives" : [ {
1849 | "name" : "include",
1850 | "description" : "Directs the executor to include this field or fragment only when the `if` argument is true",
1851 | "locations" : [ "FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT" ],
1852 | "args" : [ {
1853 | "name" : "if",
1854 | "description" : "Included when true.",
1855 | "type" : {
1856 | "kind" : "NON_NULL",
1857 | "name" : null,
1858 | "ofType" : {
1859 | "kind" : "SCALAR",
1860 | "name" : "Boolean",
1861 | "ofType" : null
1862 | }
1863 | },
1864 | "defaultValue" : null
1865 | } ],
1866 | "onOperation" : false,
1867 | "onFragment" : true,
1868 | "onField" : true
1869 | }, {
1870 | "name" : "skip",
1871 | "description" : "Directs the executor to skip this field or fragment when the `if`'argument is true.",
1872 | "locations" : [ "FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT" ],
1873 | "args" : [ {
1874 | "name" : "if",
1875 | "description" : "Skipped when true.",
1876 | "type" : {
1877 | "kind" : "NON_NULL",
1878 | "name" : null,
1879 | "ofType" : {
1880 | "kind" : "SCALAR",
1881 | "name" : "Boolean",
1882 | "ofType" : null
1883 | }
1884 | },
1885 | "defaultValue" : null
1886 | } ],
1887 | "onOperation" : false,
1888 | "onFragment" : true,
1889 | "onField" : true
1890 | }, {
1891 | "name" : "defer",
1892 | "description" : "This directive allows results to be deferred during execution",
1893 | "locations" : [ "FIELD" ],
1894 | "args" : [ ],
1895 | "onOperation" : false,
1896 | "onFragment" : false,
1897 | "onField" : true
1898 | }, {
1899 | "name" : "deprecated",
1900 | "description" : null,
1901 | "locations" : [ "FIELD_DEFINITION", "ENUM_VALUE" ],
1902 | "args" : [ {
1903 | "name" : "reason",
1904 | "description" : null,
1905 | "type" : {
1906 | "kind" : "SCALAR",
1907 | "name" : "String",
1908 | "ofType" : null
1909 | },
1910 | "defaultValue" : "\"No longer supported\""
1911 | } ],
1912 | "onOperation" : false,
1913 | "onFragment" : false,
1914 | "onField" : false
1915 | }, {
1916 | "name" : "aws_auth",
1917 | "description" : "Directs the schema to enforce authorization on a field",
1918 | "locations" : [ "FIELD_DEFINITION" ],
1919 | "args" : [ {
1920 | "name" : "cognito_groups",
1921 | "description" : "List of cognito user pool groups which have access on this field",
1922 | "type" : {
1923 | "kind" : "LIST",
1924 | "name" : null,
1925 | "ofType" : {
1926 | "kind" : "SCALAR",
1927 | "name" : "String",
1928 | "ofType" : null
1929 | }
1930 | },
1931 | "defaultValue" : null
1932 | } ],
1933 | "onOperation" : false,
1934 | "onFragment" : false,
1935 | "onField" : false
1936 | }, {
1937 | "name" : "aws_oidc",
1938 | "description" : "Tells the service this field/object has access authorized by an OIDC token.",
1939 | "locations" : [ "OBJECT", "FIELD_DEFINITION" ],
1940 | "args" : [ ],
1941 | "onOperation" : false,
1942 | "onFragment" : false,
1943 | "onField" : false
1944 | }, {
1945 | "name" : "aws_cognito_user_pools",
1946 | "description" : "Tells the service this field/object has access authorized by a Cognito User Pools token.",
1947 | "locations" : [ "OBJECT", "FIELD_DEFINITION" ],
1948 | "args" : [ {
1949 | "name" : "cognito_groups",
1950 | "description" : "List of cognito user pool groups which have access on this field",
1951 | "type" : {
1952 | "kind" : "LIST",
1953 | "name" : null,
1954 | "ofType" : {
1955 | "kind" : "SCALAR",
1956 | "name" : "String",
1957 | "ofType" : null
1958 | }
1959 | },
1960 | "defaultValue" : null
1961 | } ],
1962 | "onOperation" : false,
1963 | "onFragment" : false,
1964 | "onField" : false
1965 | }, {
1966 | "name" : "aws_publish",
1967 | "description" : "Tells the service which subscriptions will be published to when this mutation is called. This directive is deprecated use @aws_susbscribe directive instead.",
1968 | "locations" : [ "FIELD_DEFINITION" ],
1969 | "args" : [ {
1970 | "name" : "subscriptions",
1971 | "description" : "List of subscriptions which will be published to when this mutation is called.",
1972 | "type" : {
1973 | "kind" : "LIST",
1974 | "name" : null,
1975 | "ofType" : {
1976 | "kind" : "SCALAR",
1977 | "name" : "String",
1978 | "ofType" : null
1979 | }
1980 | },
1981 | "defaultValue" : null
1982 | } ],
1983 | "onOperation" : false,
1984 | "onFragment" : false,
1985 | "onField" : false
1986 | }, {
1987 | "name" : "aws_subscribe",
1988 | "description" : "Tells the service which mutation triggers this subscription.",
1989 | "locations" : [ "FIELD_DEFINITION" ],
1990 | "args" : [ {
1991 | "name" : "mutations",
1992 | "description" : "List of mutations which will trigger this subscription when they are called.",
1993 | "type" : {
1994 | "kind" : "LIST",
1995 | "name" : null,
1996 | "ofType" : {
1997 | "kind" : "SCALAR",
1998 | "name" : "String",
1999 | "ofType" : null
2000 | }
2001 | },
2002 | "defaultValue" : null
2003 | } ],
2004 | "onOperation" : false,
2005 | "onFragment" : false,
2006 | "onField" : false
2007 | }, {
2008 | "name" : "aws_api_key",
2009 | "description" : "Tells the service this field/object has access authorized by an API key.",
2010 | "locations" : [ "OBJECT", "FIELD_DEFINITION" ],
2011 | "args" : [ ],
2012 | "onOperation" : false,
2013 | "onFragment" : false,
2014 | "onField" : false
2015 | }, {
2016 | "name" : "aws_iam",
2017 | "description" : "Tells the service this field/object has access authorized by sigv4 signing.",
2018 | "locations" : [ "OBJECT", "FIELD_DEFINITION" ],
2019 | "args" : [ ],
2020 | "onOperation" : false,
2021 | "onFragment" : false,
2022 | "onField" : false
2023 | } ]
2024 | }
2025 | }
2026 | }
--------------------------------------------------------------------------------
/src/graphql/subscriptions.js:
--------------------------------------------------------------------------------
1 | // eslint-disable
2 | // this is an auto generated file. This will be overwritten
3 |
4 | export const onCreateUser = `subscription OnCreateUser {
5 | onCreateUser {
6 | id
7 | username
8 | visibility
9 | avatar {
10 | bucket
11 | region
12 | key
13 | }
14 | }
15 | }
16 | `;
17 | export const onUpdateUser = `subscription OnUpdateUser {
18 | onUpdateUser {
19 | id
20 | username
21 | visibility
22 | avatar {
23 | bucket
24 | region
25 | key
26 | }
27 | }
28 | }
29 | `;
30 | export const onDeleteUser = `subscription OnDeleteUser {
31 | onDeleteUser {
32 | id
33 | username
34 | visibility
35 | avatar {
36 | bucket
37 | region
38 | key
39 | }
40 | }
41 | }
42 | `;
43 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import * as serviceWorker from './serviceWorker';
6 |
7 | import Amplify from 'aws-amplify'
8 | import config from './aws-exports'
9 | Amplify.configure(config)
10 |
11 | ReactDOM.render(, document.getElementById('root'));
12 |
13 | // If you want your app to work offline and load faster, you can change
14 | // unregister() to register() below. Note this comes with some pitfalls.
15 | // Learn more about service workers: https://bit.ly/CRA-PWA
16 | serviceWorker.unregister();
17 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.1/8 is considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl)
104 | .then(response => {
105 | // Ensure service worker exists, and that we really are getting a JS file.
106 | const contentType = response.headers.get('content-type');
107 | if (
108 | response.status === 404 ||
109 | (contentType != null && contentType.indexOf('javascript') === -1)
110 | ) {
111 | // No service worker found. Probably a different app. Reload the page.
112 | navigator.serviceWorker.ready.then(registration => {
113 | registration.unregister().then(() => {
114 | window.location.reload();
115 | });
116 | });
117 | } else {
118 | // Service worker found. Proceed as normal.
119 | registerValidSW(swUrl, config);
120 | }
121 | })
122 | .catch(() => {
123 | console.log(
124 | 'No internet connection found. App is running in offline mode.'
125 | );
126 | });
127 | }
128 |
129 | export function unregister() {
130 | if ('serviceWorker' in navigator) {
131 | navigator.serviceWorker.ready.then(registration => {
132 | registration.unregister();
133 | });
134 | }
135 | }
136 |
--------------------------------------------------------------------------------