implement FigureResolver

master
Peter Babič 4 years ago
parent 3979750945
commit 129a4084c2
Signed by: peter.babic
GPG Key ID: 4BB075BC1884BA40
  1. 1
      .gitignore
  2. 460
      package-lock.json
  3. 5
      package.json
  4. 65
      src/integration/figure_upload.spec.ts
  5. 22
      src/integration/refresh_token.spec.ts
  6. 4
      src/server.ts
  7. 109
      src/server/FigureResolver.spec.ts
  8. 29
      src/server/FigureResolver.ts
  9. 8
      src/server/FigureResolver/Upload.ts
  10. 21
      src/server/UserResolver.spec.ts
  11. 5
      src/server/UserResolver.ts
  12. 2
      src/server/connection.ts
  13. 35
      src/server/schema.ts
  14. 80
      src/server/testing.ts

1
.gitignore vendored

@ -1,4 +1,5 @@
.vscode/
uploads/
# Created by https://www.gitignore.io/api/node
# Edit at https://www.gitignore.io/?templates=node

460
package-lock.json generated

@ -533,9 +533,9 @@
"dev": true
},
"@types/cookies": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/@types/cookies/-/cookies-0.7.2.tgz",
"integrity": "sha512-jnihWgshWystcJKrz8C9hV+Ot9lqOUyAh2RF+o3BEo6K6AS2l4zYCb9GYaBuZ3C6Il59uIGqpE3HvCun4KKeJA==",
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/@types/cookies/-/cookies-0.7.4.tgz",
"integrity": "sha512-oTGtMzZZAVuEjTwCjIh8T8FrC8n/uwy+PG0yTvQcdZ7etoel7C7/3MSd7qrukENTgQtotG7gvBlBojuVs7X5rw==",
"requires": {
"@types/connect": "*",
"@types/express": "*",
@ -583,6 +583,15 @@
"@types/node": "*"
}
},
"@types/fs-extra": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.0.1.tgz",
"integrity": "sha512-J00cVDALmi/hJOYsunyT52Hva5TnJeKP5yd1r+mH/ZU0mbYZflR0Z5kw5kITtKTRYMhm1JMClOFYdHnQszEvqw==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/glob": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz",
@ -673,9 +682,9 @@
"integrity": "sha1-/1QEYtL7TQqIRBzq8n0oewHD2Hg="
},
"@types/koa": {
"version": "2.0.49",
"resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.0.49.tgz",
"integrity": "sha512-WQWpCH8O4Dslk8IcXfazff40aM1jXX7BQRbADIj/fKozVPu76P/wQE4sRe2SCWMn8yNkOcare2MkDrnZqLMkPQ==",
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.11.0.tgz",
"integrity": "sha512-Hgx/1/rVlJvqYBrdeCsS7PDiR2qbxlMt1RnmNWD4Uxi5FF9nwkYqIldo7urjc+dfNpk+2NRGcnAYd4L5xEhCcQ==",
"requires": {
"@types/accepts": "*",
"@types/cookies": "*",
@ -686,9 +695,9 @@
}
},
"@types/koa-compose": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.4.tgz",
"integrity": "sha512-ioou0rxkuWL+yBQYsHUQAzRTfVxAg8Y2VfMftU+Y3RA03/MzuFL0x/M2sXXj3PkfnENbHsjeHR1aMdezLYpTeA==",
"version": "3.2.5",
"resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.5.tgz",
"integrity": "sha512-B8nG/OoE1ORZqCkBVsup/AKcvjdgoHnfi4pZMn5UwAPCbhk/96xyv284eBYW8JlQbQ7zDmnpFr68I/40mFoIBQ==",
"requires": {
"@types/koa": "*"
}
@ -727,6 +736,15 @@
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
"integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA=="
},
"@types/readable-stream": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.5.tgz",
"integrity": "sha512-Mq2eLkGYamlcolW603FY2ROBvcl90jPF+3jLkjpBV6qS+2aVeJqlgRG0TVAa1oWbmPdb5yOWlOPVvQle76nUNw==",
"requires": {
"@types/node": "*",
"safe-buffer": "*"
}
},
"@types/semver": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.0.2.tgz",
@ -964,6 +982,52 @@
"lru-cache": "^5.0.0"
}
},
"apollo-server-core": {
"version": "2.9.4",
"resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.9.4.tgz",
"integrity": "sha512-6mzipnn9woJxgo/JQFWTlY13svS7HCr0ZsN035eRmKOsXzROfB9ugXcTuc6MP94ICM7TlB/DtJOP+bLX53mijw==",
"requires": {
"@apollographql/apollo-tools": "^0.4.0",
"@apollographql/graphql-playground-html": "1.6.24",
"@types/graphql-upload": "^8.0.0",
"@types/ws": "^6.0.0",
"apollo-cache-control": "^0.8.4",
"apollo-datasource": "^0.6.3",
"apollo-engine-reporting": "^1.4.6",
"apollo-server-caching": "^0.5.0",
"apollo-server-env": "^2.4.3",
"apollo-server-errors": "^2.3.3",
"apollo-server-plugin-base": "^0.6.4",
"apollo-server-types": "^0.2.4",
"apollo-tracing": "^0.8.4",
"fast-json-stable-stringify": "^2.0.0",
"graphql-extensions": "^0.10.3",
"graphql-tag": "^2.9.2",
"graphql-tools": "^4.0.0",
"graphql-upload": "^8.0.2",
"sha.js": "^2.4.11",
"subscriptions-transport-ws": "^0.9.11",
"ws": "^6.0.0"
},
"dependencies": {
"fs-capacitor": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/fs-capacitor/-/fs-capacitor-2.0.4.tgz",
"integrity": "sha512-8S4f4WsCryNw2mJJchi46YgB6CR5Ze+4L1h8ewl9tEpL4SJ3ZO+c/bS4BWhB8bK+O3TMqhuZarTitd0S0eh2pA=="
},
"graphql-upload": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/graphql-upload/-/graphql-upload-8.1.0.tgz",
"integrity": "sha512-U2OiDI5VxYmzRKw0Z2dmfk0zkqMRaecH9Smh1U277gVgVe9Qn+18xqf4skwr4YJszGIh7iQDZ57+5ygOK9sM/Q==",
"requires": {
"busboy": "^0.3.1",
"fs-capacitor": "^2.0.4",
"http-errors": "^1.7.3",
"object-path": "^0.11.4"
}
}
}
},
"apollo-server-env": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/apollo-server-env/-/apollo-server-env-2.4.3.tgz",
@ -1001,33 +1065,10 @@
"type-is": "^1.6.16"
},
"dependencies": {
"apollo-server-core": {
"version": "2.9.4",
"resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.9.4.tgz",
"integrity": "sha512-6mzipnn9woJxgo/JQFWTlY13svS7HCr0ZsN035eRmKOsXzROfB9ugXcTuc6MP94ICM7TlB/DtJOP+bLX53mijw==",
"requires": {
"@apollographql/apollo-tools": "^0.4.0",
"@apollographql/graphql-playground-html": "1.6.24",
"@types/graphql-upload": "^8.0.0",
"@types/ws": "^6.0.0",
"apollo-cache-control": "^0.8.4",
"apollo-datasource": "^0.6.3",
"apollo-engine-reporting": "^1.4.6",
"apollo-server-caching": "^0.5.0",
"apollo-server-env": "^2.4.3",
"apollo-server-errors": "^2.3.3",
"apollo-server-plugin-base": "^0.6.4",
"apollo-server-types": "^0.2.4",
"apollo-tracing": "^0.8.4",
"fast-json-stable-stringify": "^2.0.0",
"graphql-extensions": "^0.10.3",
"graphql-tag": "^2.9.2",
"graphql-tools": "^4.0.0",
"graphql-upload": "^8.0.2",
"sha.js": "^2.4.11",
"subscriptions-transport-ws": "^0.9.11",
"ws": "^6.0.0"
}
"fs-capacitor": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/fs-capacitor/-/fs-capacitor-2.0.4.tgz",
"integrity": "sha512-8S4f4WsCryNw2mJJchi46YgB6CR5Ze+4L1h8ewl9tEpL4SJ3ZO+c/bS4BWhB8bK+O3TMqhuZarTitd0S0eh2pA=="
}
}
},
@ -1511,8 +1552,7 @@
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
},
"camelcase-keys": {
"version": "2.1.0",
@ -1606,90 +1646,12 @@
"mz": "^2.4.0",
"parse5": "^4.0.0",
"yargs": "^13.0.0"
},
"dependencies": {
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
},
"cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
"requires": {
"string-width": "^3.1.0",
"strip-ansi": "^5.2.0",
"wrap-ansi": "^5.1.0"
}
},
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"requires": {
"locate-path": "^3.0.0"
}
},
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
},
"string-width": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"requires": {
"emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^5.1.0"
}
},
"wrap-ansi": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
"requires": {
"ansi-styles": "^3.2.0",
"string-width": "^3.0.0",
"strip-ansi": "^5.0.0"
}
},
"yargs": {
"version": "13.2.4",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz",
"integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==",
"requires": {
"cliui": "^5.0.0",
"find-up": "^3.0.0",
"get-caller-file": "^2.0.1",
"os-locale": "^3.1.0",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^3.0.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^13.1.0"
}
},
"yargs-parser": {
"version": "13.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
"integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
}
}
},
"cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
"dev": true,
"requires": {
"string-width": "^3.1.0",
"strip-ansi": "^5.2.0",
@ -1858,19 +1820,13 @@
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"dev": true,
"requires": {
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
},
"dependencies": {
"semver": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
}
}
},
"cssom": {
@ -2136,6 +2092,7 @@
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
"integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
"dev": true,
"requires": {
"once": "^1.4.0"
}
@ -2237,6 +2194,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
"integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
"dev": true,
"requires": {
"cross-spawn": "^6.0.0",
"get-stream": "^4.0.0",
@ -2525,7 +2483,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true,
"requires": {
"locate-path": "^3.0.0"
}
@ -2543,13 +2500,13 @@
"dev": true
},
"form-data": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz",
"integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==",
"dev": true,
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
},
@ -2573,9 +2530,24 @@
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"fs-capacitor": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/fs-capacitor/-/fs-capacitor-2.0.4.tgz",
"integrity": "sha512-8S4f4WsCryNw2mJJchi46YgB6CR5Ze+4L1h8ewl9tEpL4SJ3ZO+c/bS4BWhB8bK+O3TMqhuZarTitd0S0eh2pA=="
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/fs-capacitor/-/fs-capacitor-4.0.1.tgz",
"integrity": "sha512-e0qFoKQMFe52F54dMvZLD+I1M/Gs6xB2gnZVQB5FYT/8ioP6qTb3U/tzp55O0IuPOMvSM8j4ta0bVafIFjJzxQ==",
"requires": {
"@types/readable-stream": "^2.3.5",
"readable-stream": "^3.4.0"
}
},
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"dev": true,
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
},
"fs.realpath": {
"version": "1.0.0",
@ -3138,8 +3110,7 @@
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
},
"get-stdin": {
"version": "4.0.1",
@ -3151,6 +3122,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
"integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
"dev": true,
"requires": {
"pump": "^3.0.0"
}
@ -3261,13 +3233,13 @@
}
},
"graphql-upload": {
"version": "8.0.7",
"resolved": "https://registry.npmjs.org/graphql-upload/-/graphql-upload-8.0.7.tgz",
"integrity": "sha512-gi2yygbDPXbHPC7H0PNPqP++VKSoNoJO4UrXWq4T0Bi4IhyUd3Ycop/FSxhx2svWIK3jdXR/i0vi91yR1aAF0g==",
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/graphql-upload/-/graphql-upload-9.0.0.tgz",
"integrity": "sha512-YR2o9GoDa5On3q3lYLkLo3gHfa8crCHvMY1QbT7Zqja6BUqiihqaGjbWbvSPko/gbDSmZE+zLcX46Ef+/SmRyA==",
"requires": {
"busboy": "^0.3.1",
"fs-capacitor": "^2.0.4",
"http-errors": "^1.7.2",
"fs-capacitor": "^4.0.1",
"http-errors": "^1.7.3",
"object-path": "^0.11.4"
}
},
@ -3481,11 +3453,6 @@
"loose-envify": "^1.0.0"
}
},
"invert-kv": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA=="
},
"ipaddr.js": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
@ -3647,7 +3614,8 @@
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
"dev": true
},
"is-symbol": {
"version": "1.0.2",
@ -3690,7 +3658,8 @@
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true
},
"isobject": {
"version": "3.0.1",
@ -4337,6 +4306,15 @@
"minimist": "^1.2.0"
}
},
"jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.6"
}
},
"jsonwebtoken": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
@ -4404,14 +4382,6 @@
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
"dev": true
},
"lcid": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
"integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
"requires": {
"invert-kv": "^2.0.0"
}
},
"left-pad": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",
@ -4584,14 +4554,6 @@
"tmpl": "1.0.x"
}
},
"map-age-cleaner": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
"integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
"requires": {
"p-defer": "^1.0.0"
}
},
"map-cache": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
@ -4618,16 +4580,6 @@
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"mem": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz",
"integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
"requires": {
"map-age-cleaner": "^0.1.1",
"mimic-fn": "^2.0.0",
"p-is-promise": "^2.0.0"
}
},
"meow": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
@ -4782,11 +4734,6 @@
"mime-db": "1.40.0"
}
},
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@ -4898,7 +4845,8 @@
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
"node-addon-api": {
"version": "1.7.1",
@ -4965,6 +4913,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
"integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
"dev": true,
"requires": {
"path-key": "^2.0.0"
}
@ -5121,21 +5070,6 @@
}
}
},
"os-locale": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
"integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
"requires": {
"execa": "^1.0.0",
"lcid": "^2.0.0",
"mem": "^4.0.0"
}
},
"p-defer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
"integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww="
},
"p-each-series": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz",
@ -5148,12 +5082,8 @@
"p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
},
"p-is-promise": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
"integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg=="
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
"dev": true
},
"p-limit": {
"version": "2.2.0",
@ -5235,7 +5165,8 @@
"path-key": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
"dev": true
},
"path-parse": {
"version": "1.0.6",
@ -5467,6 +5398,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"dev": true,
"requires": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
@ -5540,6 +5472,16 @@
"read-pkg": "^3.0.0"
}
},
"readable-stream": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
"integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"realpath-native": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz",
@ -5629,6 +5571,17 @@
"uuid": "^3.3.2"
},
"dependencies": {
"form-data": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"dev": true,
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
},
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
@ -5869,6 +5822,7 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
"dev": true,
"requires": {
"shebang-regex": "^1.0.0"
}
@ -5876,7 +5830,8 @@
"shebang-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true
},
"shellwords": {
"version": "0.1.1",
@ -5893,7 +5848,8 @@
"signal-exit": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true
},
"sisteransi": {
"version": "1.0.3",
@ -6206,7 +6162,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"dev": true,
"requires": {
"emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0",
@ -6231,6 +6186,14 @@
"function-bind": "^1.1.1"
}
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"requires": {
"safe-buffer": "~5.2.0"
}
},
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
@ -6248,7 +6211,8 @@
"strip-eof": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
"dev": true
},
"strip-indent": {
"version": "1.0.1",
@ -6616,21 +6580,6 @@
"yargs": "^13.2.1"
},
"dependencies": {
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
},
"cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
"requires": {
"string-width": "^3.1.0",
"strip-ansi": "^5.2.0",
"wrap-ansi": "^5.1.0"
}
},
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
@ -6644,70 +6593,10 @@
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz",
"integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w=="
},
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"requires": {
"locate-path": "^3.0.0"
}
},
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"string-width": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"requires": {
"emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^5.1.0"
}
},
"wrap-ansi": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
"requires": {
"ansi-styles": "^3.2.0",
"string-width": "^3.0.0",
"strip-ansi": "^5.0.0"
}
},
"yargs": {
"version": "13.2.4",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz",
"integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==",
"requires": {
"cliui": "^5.0.0",
"find-up": "^3.0.0",
"get-caller-file": "^2.0.1",
"os-locale": "^3.1.0",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^3.0.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^13.1.0"
}
},
"yargs-parser": {
"version": "13.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
"integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
}
}
},
@ -6749,6 +6638,12 @@
"set-value": "^2.0.1"
}
},
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
"dev": true
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@ -6815,6 +6710,11 @@
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
"dev": true
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"util.promisify": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz",
@ -6925,6 +6825,7 @@
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"dev": true,
"requires": {
"isexe": "^2.0.0"
}
@ -6944,7 +6845,6 @@
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.0",
"string-width": "^3.0.0",
@ -7061,7 +6961,6 @@
"version": "13.3.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz",
"integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==",
"dev": true,
"requires": {
"cliui": "^5.0.0",
"find-up": "^3.0.0",
@ -7079,7 +6978,6 @@
"version": "13.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
"integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
"dev": true,
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"

@ -19,6 +19,7 @@
"dotenv": "^8.1.0",
"express": "^4.17.1",
"graphql": "^14.5.4",
"graphql-upload": "^9.0.0",
"jsonwebtoken": "^8.5.1",
"pg": "^7.12.1",
"reflect-metadata": "^0.1.13",
@ -28,11 +29,15 @@
"devDependencies": {
"@types/cookie": "^0.3.3",
"@types/express": "^4.17.1",
"@types/fs-extra": "^8.0.1",
"@types/graphql": "^14.5.0",
"@types/graphql-upload": "^8.0.3",
"@types/jest": "^24.0.18",
"@types/jsonwebtoken": "^8.3.3",
"@types/node": "^12.7.5",
"@types/node-fetch": "^2.5.2",
"form-data": "^3.0.0",
"fs-extra": "^8.1.0",
"graphql-request": "^1.8.2",
"jest": "^24.9.0",
"node-fetch": "^2.6.0",

@ -0,0 +1,65 @@
import fetch from "node-fetch"
import { gqlUri, uploadDir } from "../server/testing"
import FormData = require("form-data")
import fs = require("fs-extra")
describe("figure upload integration should", () => {
it("upload a file", async () => {
const filename = "ok.png"
const path = uploadDir + filename
const body = bodyFrom(filename)
const reponse = await fetchWith(body)
const uploadedFile = await fs.access(path, fs.constants.F_OK)
expect(uploadedFile).toBeUndefined()
expect(reponse.errors).toBeUndefined()
expect(reponse.data).toMatchObject({ uploadFigure: true })
})
it("revoke a non-picture file", async () => {
const filename = "file.txt"
const path = uploadDir + filename
const body = bodyFrom(filename)
const response = await fetchWith(body)
await expect(fs.access(path, fs.constants.F_OK)).rejects.toThrow()
expect(response.errors).toBeDefined()
expect(response.data).toBeNull()
})
})
const fetchWith = async (body: FormData): Promise<FetchResponse> => {
const reponse = await fetch(gqlUri, {
method: "POST",
body,
})
return reponse.json()
}
const bodyFrom = (filename: string) => {
const body = new FormData()
body.append(
"operations",
JSON.stringify({
query: /* GraphQL */ `
mutation($file: Upload!) {
uploadFigure(file: $file)
}
`,
variables: {
file: null,
},
})
)
body.append("map", JSON.stringify({ 0: ["variables.file"] }))
body.append("0", "", { filename })
return body
}
interface FetchResponse {
data: any
errors?: any
}

@ -1,18 +1,22 @@
// TODO: convert to import
import cookie = require("cookie")
import { gql } from "apollo-server-express"
import { GraphQLClient, rawRequest } from "graphql-request"
import fetch from "node-fetch"
import { createConnection } from "typeorm"
import { createServer } from "./server"
import { gqlToStr } from "./server/schema"
import { testingConnectionOptions } from "./server/testing"
import { createServer } from "../server"
import { gqlToStr } from "../server/schema"
import {
gqlUri,
refreshTokenUri,
testingConnectionOptions,
testingPort,
} from "../server/testing"
import {
rtCookieOptions,
signRefreshToken,
verifiedRefreshTokenPayload,
} from "./server/userResolver/auth"
import { User } from "./server/userResolver/User"
} from "../server/UserResolver/auth"
import { User } from "../server/UserResolver/User"
let user: User
@ -107,7 +111,7 @@ describe("server should", () => {
beforeAll(async () => {
await createConnection(testingConnectionOptions())
await createServer(port)
await createServer(testingPort)
await User.delete({ email: "auth@server.com" })
user = await User.create({ email: "auth@server.com", password: "password" }).save()
@ -117,10 +121,6 @@ afterAll(async () => {
await User.delete({ email: "auth@server.com" })
})
const port = 4001
const gqlUri = `http://localhost:${port}/graphql`
const refreshTokenUri = `http://localhost:${port}/refresh_token`
const accessTokenMutation = gql`
mutation {
accessToken(email: "auth@server.com", password: "password")

@ -5,8 +5,8 @@ import {
accessTokenWithRefreshCookie,
contextFunction,
verifiedRefreshTokenPayload,
} from "./server/userResolver/auth"
import { User } from "./server/userResolver/User"
} from "./server/UserResolver/auth"
import { User } from "./server/UserResolver/User"
import cookie = require("cookie")
import cors = require("cors")

@ -0,0 +1,109 @@
import { gql } from "apollo-server-express"
import { Readable, Stream } from "stream"
import { createConnection, getConnection } from "typeorm"
import { Upload } from "./FigureResolver/Upload"
import { callSchema } from "./schema"
import {
context,
initializeRollbackTransactions,
runInRollbackTransaction,
testingConnectionOptions,
uploadDir,
} from "./testing"
import fs = require("fs-extra")
describe("resolver of figures should", () => {
it(
"return an error when wrong file extension is provided",
runInRollbackTransaction(async () => {
const filename = "wrong_extensions.txt"
const file: Upload = {
filename,
mimetype: "image/text",
encoding: "7bit",
createReadStream: () => new Stream(),
}
const response = await callSchema(uploadFileMutation, context(), {
file,
})
expect(response.errors).toBeDefined()
expect(response.data).toBeNull()
await expect(fs.stat(uploadDir + filename)).rejects.toThrow()
})
)
it(
"return an error when error occurs during streaming",
runInRollbackTransaction(async () => {
const filename = "stream_error.png"
const file: Upload = {
filename,
mimetype: "image/png",
encoding: "7bit",
createReadStream: () => {
const stream = new Readable({
objectMode: true,
read() {},
})
stream.push("file contents")
stream.destroy(new Error("readable stream error"))
return stream
},
}
const response = await callSchema(uploadFileMutation, context(), {
file,
})
expect(response.errors).toBeDefined()
expect(response.data).toBeNull()
await expect(fs.stat(uploadDir + filename)).resolves.toBeTruthy()
})
)
it(
"return truthy when ok",
runInRollbackTransaction(async () => {
const filename = "truthy.png"
const file: Upload = {
filename,
mimetype: "image/png",
encoding: "7bit",
createReadStream: () => {
const stream = new Readable({
objectMode: true,
autoDestroy: true,
read() {},
})
stream.push(null)
return stream
},
}
const response = await callSchema(uploadFileMutation, context(), {
file,
})
expect(response.errors).toBeUndefined()
expect(response.data).toMatchObject({ uploadFigure: true })
await expect(fs.stat(uploadDir + filename)).resolves.toBeTruthy()
})
)
})
beforeAll(async () => {
initializeRollbackTransactions()
await createConnection(testingConnectionOptions())
await fs.emptyDir(uploadDir)
})
afterAll(async () => {
await getConnection().close()
// await fs.emptyDir(uploadDir)
})
const uploadFileMutation = gql`
mutation($file: Upload!) {
uploadFigure(file: $file)
}
`

@ -0,0 +1,29 @@
import { createWriteStream } from "fs-extra"
import { GraphQLUpload } from "graphql-upload"
import { pipeline } from "stream"
import { Arg, Mutation } from "type-graphql"
import { Upload } from "./FigureResolver/Upload"
import path = require("path")
export class FigureResolver {
@Mutation(() => Boolean)
async uploadFigure(
@Arg("file", () => GraphQLUpload)
{ createReadStream, filename }: Upload
) {
const allowedExt = [".jpg", ".png"]
const ext = path.extname(filename)
if (!allowedExt.includes(ext)) {
throw new Error("wrong extension")
}
return new Promise((resolve, reject) =>
pipeline(
createReadStream() as any,
createWriteStream(__dirname + "/../../uploads/" + filename),
error => (error ? reject(error) : resolve(true))
)
)
}
}

@ -0,0 +1,8 @@
import { Stream } from "stream"
export interface Upload {
filename: string
mimetype: string
encoding: string
createReadStream: () => Stream
}

@ -1,14 +1,15 @@
import { gql } from "apollo-server-express"
import { Request, Response } from "express"
import { createConnection, getConnection } from "typeorm"
import { callSchema } from "./schema"
import {
contextWithAuthHeader,
contextWithCookie,
initializeRollbackTransactions,
runInRollbackTransaction,
testingConnectionOptions,
} from "./testing"
import { Context, signAccessToken, verifiedAccessTokenPayload } from "./userResolver/auth"
import { User } from "./userResolver/User"
import { signAccessToken, verifiedAccessTokenPayload } from "./UserResolver/auth"
import { User } from "./UserResolver/User"
describe("resolver of user", () => {
describe("createUser mutation should", () => {
@ -161,17 +162,3 @@ const signOutMutation = gql`
signOut
}
`
const contextWithAuthHeader = (header: string): Context => ({
req: {
headers: {
authorization: header,
},
} as Request,
res: {} as Response,
})
const contextWithCookie = (): Context => ({
req: {} as Request,
res: ({ cookie: () => undefined } as unknown) as Response,
})

@ -5,10 +5,11 @@ import {
comparePasswords,
Context,
createRtCookie,
} from "./userResolver/auth"
import { User } from "./userResolver/User"
} from "./UserResolver/auth"
import { User } from "./UserResolver/User"
export class UserResolver {
// TODO: remove when other query gets itroduced
@Query(() => String)
async query() {
return ""

@ -1,5 +1,5 @@
import { ConnectionOptions } from "typeorm"
import { User } from "./userResolver/User"
import { User } from "./UserResolver/User"
export const connectionOptions = (): ConnectionOptions => ({
type: "postgres",

@ -1,27 +1,34 @@
require("dotenv").config()
import { DocumentNode, graphql, GraphQLSchema } from "graphql"
import { buildSchema } from "type-graphql"
import { FigureResolver } from "./FigureResolver"
import { UserResolver } from "./UserResolver"
import { Context, customAuthChecker } from "./userResolver/auth"
import { Context, customAuthChecker } from "./UserResolver/auth"
let schema: GraphQLSchema
export const callSchema = async (document: DocumentNode, context?: Context) => {
if (!schema) {
schema = await createSchema()
}
export const callSchema = async (
document: DocumentNode,
context?: Context,
variables?: any
) => {
if (!schema) {
schema = await createSchema()
}
return graphql({
schema,
source: gqlToStr(document),
contextValue: context,
})
return graphql({
schema,
source: gqlToStr(document),
contextValue: context,
variableValues: variables,
})
}
export const createSchema = () =>
buildSchema({
resolvers: [UserResolver],
authChecker: customAuthChecker,
})
buildSchema({
resolvers: [UserResolver, FigureResolver],
authChecker: customAuthChecker,
validate: false,
})
export const gqlToStr = (document: DocumentNode) => document.loc!.source.body as string

@ -1,50 +1,76 @@
import { Request, Response } from "express"
import { ConnectionOptions } from "typeorm"
import {
initializeTransactionalContext,
patchTypeORMRepositoryWithBaseRepository,
Propagation,
Transactional,
initializeTransactionalContext,
patchTypeORMRepositoryWithBaseRepository,
Propagation,
Transactional,
} from "typeorm-transactional-cls-hooked"
import { connectionOptions } from "./connection"
import { Context } from "./UserResolver/auth"
export const testingPort = 4001
export const gqlUri = `http://localhost:${testingPort}/graphql`
export const refreshTokenUri = `http://localhost:${testingPort}/refresh_token`
export const uploadDir = __dirname + "/../../uploads/"
export const testingConnectionOptions = () => {
const database = process.env.DB_NAME_TESING as string
const database = process.env.DB_NAME_TESING as string
return { ...connectionOptions(), database } as ConnectionOptions
return { ...connectionOptions(), database } as ConnectionOptions
}
export const context = (): Context => ({
req: {} as Request,
res: {} as Response,
})
export const contextWithAuthHeader = (header: string): Context => ({
req: {
headers: {
authorization: header,
},
} as Request,
res: {} as Response,
})
export const contextWithCookie = (): Context => ({
req: {} as Request,
res: ({ cookie: () => undefined } as unknown) as Response,
})
export const initializeRollbackTransactions = () => {
initializeTransactionalContext()
patchTypeORMRepositoryWithBaseRepository()
initializeTransactionalContext()
patchTypeORMRepositoryWithBaseRepository()
}
type RunFunction = () => Promise<void> | void
class RollbackError extends Error {
constructor(message: string) {
super(message)
constructor(message: string) {
super(message)
this.name = this.constructor.name
}
this.name = this.constructor.name
}
}
class TransactionCreator {
@Transactional({ propagation: Propagation.REQUIRED })
static async run(func: RunFunction) {
await func()
throw new RollbackError(`This is thrown to cause a rollback on the transaction.`)
}
@Transactional({ propagation: Propagation.REQUIRED })
static async run(func: RunFunction) {
await func()
throw new RollbackError(`This is thrown to cause a rollback on the transaction.`)
}
}
export function runInRollbackTransaction(func: RunFunction) {
return async () => {
try {
await TransactionCreator.run(func)
} catch (e) {
/* istanbul ignore next */
if (!(e instanceof RollbackError)) {
throw e
}
}
}
return async () => {
try {
await TransactionCreator.run(func)
} catch (e) {
/* istanbul ignore next */
if (!(e instanceof RollbackError)) {
throw e
}
}
}
}

Loading…
Cancel
Save