Merge branch 'develop'

This commit is contained in:
Barry Low committed 2018-10-04 02:03:31 -07:00
commit a881bc08e8
40 files changed
+2437 -720

No files matched your search

+1 -1
View File
@@ -14,7 +14,7 @@ Advanced Algos LTD. is publishing the code of this software for several reasons.
it shall not be considered free software yet. Advanced Algos LTD. is a for-profit company
in the crypto space and this module is still proprietary software.
The reasons for opening up the code of AACloud at this stage are the following:
The reasons for opening up the code of this module at this stage are the following:
* We believe that transparency is paramount to achieving our goals, so we want everyone
to be able to understand what this module does and how. Opening up the code of this module allows
+1
View File
@@ -41,6 +41,7 @@ type TeamProfile {
description: String
motto: String
avatar: String
banner: String
updatedAt: DateTime!
createdAt: DateTime!
}
+1 -4
View File
@@ -1,10 +1,7 @@
version: '3'
services:
api:
image: aateamapi-dev:v1
build:
context: .
dockerfile: ./Dockerfile
image: advancedalgosteamsmodule/teammodule-api:v1
env_file: ./.env
container_name: aateamapi
tty: true
+402 -54
View File
@@ -3,6 +3,14 @@
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"@azure/storage-blob": {
"version": "10.0.0-preview",
"resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-10.0.0-preview.tgz",
"integrity": "sha512-PFXKm+gipKDfg5h08hPiEr0Za4RMiFzzte+ewh4ACZeRQa0XZK55NAZxW67ZytGBd7WXdQq6pcAgo5dBnwQANQ==",
"requires": {
"ms-rest-js": "0.21.413"
}
},
"@babel/generator": {
"version": "7.0.0-beta.38",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.38.tgz",
@@ -213,6 +221,14 @@
"@types/express": "*"
}
},
"@types/form-data": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz",
"integrity": "sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ==",
"requires": {
"@types/node": "*"
}
},
"@types/graphql": {
"version": "0.12.6",
"resolved": "http://registry.npmjs.org/@types/graphql/-/graphql-0.12.6.tgz",
@@ -247,6 +263,14 @@
"@types/mime": "*"
}
},
"@types/uuid": {
"version": "3.4.4",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.4.tgz",
"integrity": "sha512-tPIgT0GUmdJQNSHxp0X2jnpQfBSTfGxUMc/2CXBU2mnyTFVYVa2ojpoQ74w0U2yn2vw3jnC640+77lkFFpdVDw==",
"requires": {
"@types/node": "*"
}
},
"@types/zen-observable": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.5.4.tgz",
@@ -808,6 +832,86 @@
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
},
"axios": {
"version": "0.18.0",
"resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
"integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
"requires": {
"follow-redirects": "^1.3.0",
"is-buffer": "^1.1.5"
}
},
"azure-storage": {
"version": "2.10.1",
"resolved": "https://registry.npmjs.org/azure-storage/-/azure-storage-2.10.1.tgz",
"integrity": "sha512-rnFo1uMIPtilusRCpK91tfY3P4Q7qRsDNwriXdp+OeTIGkGt0cTxL4mhqYfNPYPK+WBQmBdGWhOk+iROM05dcw==",
"requires": {
"browserify-mime": "~1.2.9",
"extend": "~1.2.1",
"json-edm-parser": "0.1.2",
"md5.js": "1.3.4",
"readable-stream": "~2.0.0",
"request": "^2.86.0",
"underscore": "~1.8.3",
"uuid": "^3.0.0",
"validator": "~9.4.1",
"xml2js": "0.2.8",
"xmlbuilder": "0.4.3"
},
"dependencies": {
"extend": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/extend/-/extend-1.2.1.tgz",
"integrity": "sha1-oPX9bPyDpf5J72mNYOyKYk3UV2w="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"process-nextick-args": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
},
"readable-stream": {
"version": "2.0.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
"integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "~1.0.0",
"process-nextick-args": "~1.0.6",
"string_decoder": "~0.10.x",
"util-deprecate": "~1.0.1"
}
},
"sax": {
"version": "0.5.8",
"resolved": "http://registry.npmjs.org/sax/-/sax-0.5.8.tgz",
"integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE="
},
"validator": {
"version": "9.4.1",
"resolved": "http://registry.npmjs.org/validator/-/validator-9.4.1.tgz",
"integrity": "sha512-YV5KjzvRmSyJ1ee/Dm5UED0G+1L4GZnLN3w6/T+zZm8scVua4sOhYKWTUrKa0H/tMiJyO9QLHMPN+9mB/aMunA=="
},
"xml2js": {
"version": "0.2.8",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.2.8.tgz",
"integrity": "sha1-m4FpCTFjH/CdGVdUn69U9PmAs8I=",
"requires": {
"sax": "0.5.x"
}
},
"xmlbuilder": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-0.4.3.tgz",
"integrity": "sha1-xGFLp04K0ZbmCcknLNnh3bKKilg="
}
}
},
"babel-runtime": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
@@ -968,6 +1072,21 @@
"qs": "6.5.2",
"raw-body": "2.3.3",
"type-is": "~1.6.16"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"body-parser-graphql": {
@@ -1028,6 +1147,11 @@
}
}
},
"browserify-mime": {
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/browserify-mime/-/browserify-mime-1.2.9.tgz",
"integrity": "sha1-rrGvKN5sDXpqLOQK22j/GEIq8x8="
},
"buffer": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
@@ -1746,18 +1870,11 @@
"integrity": "sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw=="
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.0.1.tgz",
"integrity": "sha512-K23FHJ/Mt404FSlp6gSZCevIbTMLX0j3fmHhUEhQ3Wq0FMODW3+cUSoLdy1Gx4polAf4t/lphhmHH35BB8cLYw==",
"requires": {
"ms": "2.0.0"
},
"dependencies": {
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
"ms": "^2.1.1"
}
},
"decamelize": {
@@ -2271,6 +2388,14 @@
"to-regex": "^3.0.1"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"define-property": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
@@ -2286,6 +2411,11 @@
"requires": {
"is-extendable": "^0.1.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
@@ -2409,11 +2539,24 @@
"type-is": "~1.6.15"
}
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"iconv-lite": {
"version": "0.4.19",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
"integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"qs": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
@@ -2680,6 +2823,14 @@
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
},
"fast-xml-parser": {
"version": "3.12.5",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-3.12.5.tgz",
"integrity": "sha512-g8TSGUF1a2vdFmQ29vKcYBNnwuJQQuyr6It3cjGsiD3dkUXqVWuXZQvjEkgrrCe5K8D30X125ACyxaj7XaaH8g==",
"requires": {
"nimnjs": "^1.3.2"
}
},
"fd-slicer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
@@ -2762,6 +2913,19 @@
"unpipe": "~1.0.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"statuses": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
@@ -2786,6 +2950,29 @@
"locate-path": "^2.0.0"
}
},
"follow-redirects": {
"version": "1.5.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.8.tgz",
"integrity": "sha512-sy1mXPmv7kLAMKW/8XofG7o9T+6gAjzdZK4AJF6ryqQYUa/hnzgiypoeUecZ53x7XiqKNEpNqLtS97MshW2nxg==",
"requires": {
"debug": "=3.1.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@@ -4225,6 +4412,15 @@
}
}
},
"hash-base": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
"integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=",
"requires": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
}
},
"header-case": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz",
@@ -4822,6 +5018,14 @@
"integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=",
"dev": true
},
"json-edm-parser": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/json-edm-parser/-/json-edm-parser-0.1.2.tgz",
"integrity": "sha1-HmCw/vG8CvZ7wNFG393lSGzWFbQ=",
"requires": {
"jsonparse": "~1.2.0"
}
},
"json-parse-better-errors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
@@ -4898,6 +5102,11 @@
"integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
"dev": true
},
"jsonparse": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.2.0.tgz",
"integrity": "sha1-XAxWhRBxYOcv50ib3eoLRMK8Z70="
},
"jsonwebtoken": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.3.0.tgz",
@@ -4946,6 +5155,23 @@
"lru-memoizer": "^1.6.0",
"ms": "^2.0.0",
"request": "^2.73.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
},
"dependencies": {
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
}
}
},
"jws": {
@@ -5405,6 +5631,15 @@
"integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=",
"dev": true
},
"md5.js": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz",
"integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=",
"requires": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1"
}
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -5419,9 +5654,9 @@
}
},
"memfs": {
"version": "2.9.4",
"resolved": "https://registry.npmjs.org/memfs/-/memfs-2.9.4.tgz",
"integrity": "sha512-wstvgqSTBGf9rQHoaRpX3wJiGzB/sj649XaO+byuHiPZQaR3Y/mOgU6n9iMFLtAHlR4BwwBWFgA4hobiU6EcCg==",
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/memfs/-/memfs-2.10.0.tgz",
"integrity": "sha512-GuQXfXghDdDdkokv6cwaWLh8bOD9Ots4z11qUR9yKiCeO7oMPhBjFjKVc991DIHTXFbonqKYOEDAVTa4CvvkJg==",
"dev": true,
"requires": {
"fast-extend": "0.0.2",
@@ -5555,6 +5790,30 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
},
"ms-rest-js": {
"version": "0.21.413",
"resolved": "https://registry.npmjs.org/ms-rest-js/-/ms-rest-js-0.21.413.tgz",
"integrity": "sha512-eX+M98Y9s+zo85Unt83TYkpuJkW4d0wuiHrpWjAxx/7YzZd3uVq8HRhJHXGDqCd22nlEvtwlchfgwILmBcWnOg==",
"requires": {
"@types/express": "^4.11.1",
"@types/form-data": "^2.2.1",
"@types/node": "^9.4.6",
"@types/uuid": "^3.4.3",
"axios": "^0.18.0",
"form-data": "^2.3.2",
"tough-cookie": "^2.4.3",
"tslib": "^1.9.2",
"uuid": "^3.2.1",
"xml2js": "^0.4.19"
},
"dependencies": {
"@types/node": {
"version": "9.6.31",
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.31.tgz",
"integrity": "sha512-kIVlvUBizL51ALNMPbmcZoM7quHyB7J6fLRwQe22JsMp39nrVSHdBeVVS3fnQCK1orxI3O8LScmb8cuiihkAfA=="
}
}
},
"multimatch": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz",
@@ -5608,6 +5867,25 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
"nimn-date-parser": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/nimn-date-parser/-/nimn-date-parser-1.0.0.tgz",
"integrity": "sha512-1Nf+x3EeMvHUiHsVuEhiZnwA8RMeOBVTQWfB1S2n9+i6PYCofHd2HRMD+WOHIHYshy4T4Gk8wQoCol7Hq3av8Q=="
},
"nimn_schema_builder": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/nimn_schema_builder/-/nimn_schema_builder-1.1.0.tgz",
"integrity": "sha512-DK5/B8CM4qwzG2URy130avcwPev4uO0ev836FbQyKo1ms6I9z/i6EJyiZ+d9xtgloxUri0W+5gfR8YbPq7SheA=="
},
"nimnjs": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/nimnjs/-/nimnjs-1.3.2.tgz",
"integrity": "sha512-TIOtI4iqkQrUM1tiM76AtTQem0c7e56SkDZ7sj1d1MfUsqRcq2ZWQvej/O+HBTZV7u/VKnwlKTDugK/75IRPPw==",
"requires": {
"nimn-date-parser": "^1.0.0",
"nimn_schema_builder": "^1.0.0"
}
},
"no-case": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
@@ -6330,6 +6608,23 @@
"async": "^1.5.2",
"debug": "^2.2.0",
"mkdirp": "0.5.x"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
}
}
},
"posix-character-classes": {
@@ -6338,9 +6633,9 @@
"integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
},
"postgres-array": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-1.0.2.tgz",
"integrity": "sha1-jgsy6wO/d6XAp4UeBEHBaaJWojg=",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-1.0.3.tgz",
"integrity": "sha512-5wClXrAP0+78mcsNX3/ithQ5exKvCyK5lr5NEEEeGwwM6NJdQgzIJBVxLvRW+huFpX92F2QnZ5CcokH0VhK2qQ==",
"dev": true
},
"postgres-bytea": {
@@ -6376,14 +6671,14 @@
"dev": true
},
"prisma": {
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/prisma/-/prisma-1.16.0.tgz",
"integrity": "sha512-8jZYCrkd1xjy+JJbQi81f8PBOLe8LLWwSu0fK0cqekm3FeafBd8xk5b0RWcIsHyVd6ypKCQt3tnZEMVzmbKrdQ==",
"version": "1.16.4",
"resolved": "https://registry.npmjs.org/prisma/-/prisma-1.16.4.tgz",
"integrity": "sha512-ha+SJDnJ+NVtkoP4nivcmnKV/PmkbQiXVJUPEdYfkQPpuite1kOuFp9seolE4DJFaz3m8DlF24AQf7aePf09AQ==",
"dev": true,
"requires": {
"fs-extra": "^5.0.0",
"prisma-cli-core": "1.0.76",
"prisma-cli-engine": "1.0.79",
"prisma-cli-core": "1.0.79",
"prisma-cli-engine": "1.0.82",
"semver": "^5.4.1",
"source-map-support": "^0.4.18"
},
@@ -6502,9 +6797,9 @@
}
},
"prisma-cli-core": {
"version": "1.0.76",
"resolved": "https://registry.npmjs.org/prisma-cli-core/-/prisma-cli-core-1.0.76.tgz",
"integrity": "sha512-HtHn/RM2GlJi23KoIXHoboP97aC54SYDqr7B4uT/80JP6A6nQp5HLt4sJgNfKapaHFZVzXYM7M3LEfGq3tgQbw==",
"version": "1.0.79",
"resolved": "https://registry.npmjs.org/prisma-cli-core/-/prisma-cli-core-1.0.79.tgz",
"integrity": "sha512-3xaFE0wK48nZ8LOqx62gMoFgjIob121Uo6RHOnXNXMcCOdtGM7VfGw4o6gyDVwNDvu66fz0EVLaQGcJb5hnTpA==",
"dev": true,
"requires": {
"adm-zip": "^0.4.7",
@@ -6538,9 +6833,9 @@
"opn": "^5.1.0",
"pause": "^0.1.0",
"portfinder": "^1.0.13",
"prisma-db-introspection": "0.0.46",
"prisma-db-introspection": "0.0.50",
"prisma-json-schema": "0.0.4",
"prisma-yml": "1.0.96",
"prisma-yml": "1.0.100",
"scuid": "^1.0.2",
"semver": "^5.4.1",
"sillyname": "^0.1.0",
@@ -6646,12 +6941,12 @@
}
},
"graphql-config": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/graphql-config/-/graphql-config-2.1.0.tgz",
"integrity": "sha512-LWpkME3x+KSFMVuMpRmDHTIZLyQQsBoKtMXJrT4RgXk6y0GRf0lsJ81R3S2FmT1CKZQOJfFsOpUfPpAcfmoN/A==",
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/graphql-config/-/graphql-config-2.2.1.tgz",
"integrity": "sha512-U8+1IAhw9m6WkZRRcyj8ZarK96R6lQBQ0an4lp76Ps9FyhOXENC5YQOxOFGm5CxPrX2rD0g3Je4zG5xdNJjwzQ==",
"dev": true,
"requires": {
"graphql-import": "^0.4.4",
"graphql-import": "^0.7.1",
"graphql-request": "^1.5.0",
"js-yaml": "^3.10.0",
"lodash": "^4.17.4",
@@ -6697,12 +6992,13 @@
}
},
"graphql-import": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/graphql-import/-/graphql-import-0.4.5.tgz",
"integrity": "sha512-G/+I08Qp6/QGTb9qapknCm3yPHV0ZL7wbaalWFpxsfR8ZhZoTBe//LsbsCKlbALQpcMegchpJhpTSKiJjhaVqQ==",
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/graphql-import/-/graphql-import-0.7.1.tgz",
"integrity": "sha512-YpwpaPjRUVlw2SN3OPljpWbVRWAhMAyfSba5U47qGMOSsPLi2gYeJtngGpymjm9nk57RFWEpjqwh4+dpYuFAPw==",
"dev": true,
"requires": {
"lodash": "^4.17.4"
"lodash": "^4.17.4",
"resolve-from": "^4.0.0"
}
},
"inquirer": {
@@ -6778,9 +7074,9 @@
"dev": true
},
"prisma-yml": {
"version": "1.0.96",
"resolved": "https://registry.npmjs.org/prisma-yml/-/prisma-yml-1.0.96.tgz",
"integrity": "sha512-w3XGzJHUq5pwBoFy/amkGOcTDj4XoHh8UFUUUZcHo5fSyoF8AWeRTu1yWINaPVGxbcmpwKNetntAW4ijiq7M5g==",
"version": "1.0.100",
"resolved": "https://registry.npmjs.org/prisma-yml/-/prisma-yml-1.0.100.tgz",
"integrity": "sha512-W2a0dpfbXyapc3WZqcvUBqtsl2r9upQRUR2p53AqQR4tQz+/6nsMcqe30vqgnOW/WmNAnknqQT3Z5P0rsq4K3Q==",
"dev": true,
"requires": {
"ajv": "5",
@@ -6803,6 +7099,12 @@
"yaml-ast-parser": "^0.0.40"
}
},
"resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"dev": true
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -6827,9 +7129,9 @@
}
},
"prisma-cli-engine": {
"version": "1.0.79",
"resolved": "https://registry.npmjs.org/prisma-cli-engine/-/prisma-cli-engine-1.0.79.tgz",
"integrity": "sha512-CdEIJs4ld1IiQQt2CFFPmeDypN4Ct4sTgmFODVjJix790mpEtxMagzCcA+mhfnRL65P6xiHn76Gdxbz60GyYBA==",
"version": "1.0.82",
"resolved": "https://registry.npmjs.org/prisma-cli-engine/-/prisma-cli-engine-1.0.82.tgz",
"integrity": "sha512-kEqNtH0bjzVX17Vcs77UiAwk0Ei9Za03bOINcrpIjNUyI9GOOU5p+6ss8cePfK21lxvy5RSlYwthBFLkXE73Gg==",
"dev": true,
"requires": {
"@heroku/linewrap": "^1.0.0",
@@ -6872,7 +7174,7 @@
"memfs": "^2.5.3",
"opn": "^5.1.0",
"prisma-json-schema": "0.0.4",
"prisma-yml": "1.0.96",
"prisma-yml": "1.0.100",
"raven": "2.3.0",
"replaceall": "^0.1.6",
"rwlockfile": "^1.4.8",
@@ -6937,9 +7239,9 @@
"dev": true
},
"prisma-yml": {
"version": "1.0.96",
"resolved": "https://registry.npmjs.org/prisma-yml/-/prisma-yml-1.0.96.tgz",
"integrity": "sha512-w3XGzJHUq5pwBoFy/amkGOcTDj4XoHh8UFUUUZcHo5fSyoF8AWeRTu1yWINaPVGxbcmpwKNetntAW4ijiq7M5g==",
"version": "1.0.100",
"resolved": "https://registry.npmjs.org/prisma-yml/-/prisma-yml-1.0.100.tgz",
"integrity": "sha512-W2a0dpfbXyapc3WZqcvUBqtsl2r9upQRUR2p53AqQR4tQz+/6nsMcqe30vqgnOW/WmNAnknqQT3Z5P0rsq4K3Q==",
"dev": true,
"requires": {
"ajv": "5",
@@ -6995,9 +7297,9 @@
}
},
"prisma-db-introspection": {
"version": "0.0.46",
"resolved": "https://registry.npmjs.org/prisma-db-introspection/-/prisma-db-introspection-0.0.46.tgz",
"integrity": "sha512-/b7evS9b5xKS7UrcOERkCmV+IWC6OAgFtInFsvdwn4MeLEaVbkOfzRakdOo+t2gb+N7Yy8Eey9eKYgB5jiJAbA==",
"version": "0.0.50",
"resolved": "https://registry.npmjs.org/prisma-db-introspection/-/prisma-db-introspection-0.0.50.tgz",
"integrity": "sha512-coeJ3SRumezVnsQwc/kwNzxWFUBKHNwnD+keUJeZFFY3j7EDtRFHoL5DD7vTREvMEugoWOiovc+MYHFkDt0l+w==",
"dev": true,
"requires": {
"ajv": "5",
@@ -7637,6 +7939,14 @@
"statuses": "~1.4.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
@@ -7799,6 +8109,14 @@
"use": "^3.1.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"define-property": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
@@ -7815,6 +8133,11 @@
"is-extendable": "^0.1.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -8061,9 +8384,9 @@
"dev": true
},
"string-similarity": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/string-similarity/-/string-similarity-1.2.1.tgz",
"integrity": "sha512-XqC6lRZF3UIYdxBRHjIfJwU2nYzPm+E8udKFHjIplnRQflkXP1A1Ie3HoEv04W/zY1wGnV6TQpklM2WwZO3gIA==",
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/string-similarity/-/string-similarity-1.2.2.tgz",
"integrity": "sha512-IoHUjcw3Srl8nsPlW04U3qwWPk3oG2ffLM0tN853d/E/JlIvcmZmDY2Kz5HzKp4lEi2T7QD7Zuvjq/1rDw+XcQ==",
"dev": true,
"requires": {
"lodash.every": "^4.6.0",
@@ -8463,6 +8786,11 @@
"yn": "^2.0.0"
}
},
"tslib": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
"integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ=="
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@@ -8492,9 +8820,9 @@
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og=="
},
"unbzip2-stream": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz",
"integrity": "sha512-izD3jxT8xkzwtXRUZjtmRwKnZoeECrfZ8ra/ketwOcusbZEp4mjULMnJOCfTDZBgGQAAY1AJ/IgxcwkavcX9Og==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.0.tgz",
"integrity": "sha512-kE2WkurNnPUMcryNioS68DDbhoPB8Qxsd8btHSj+sd5Pjh2GsjmeHLzMSqV9HHziAo8FzVxVCJl9ZYhk7yY1pA==",
"dev": true,
"requires": {
"buffer": "^3.0.1",
@@ -8532,8 +8860,28 @@
"integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=",
"requires": {
"debug": "^2.2.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"underscore": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
},
"union-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
+5 -1
View File
@@ -7,9 +7,13 @@
"dev": "npm-run-all --parallel debug playground"
},
"dependencies": {
"@azure/storage-blob": "^10.0.0-preview",
"azure-storage": "^2.10.1",
"cors": "^2.8.4",
"debug": "^4.0.1",
"dotenv": "^6.0.0",
"express-jwt": "^5.3.1",
"fast-xml-parser": "^3.12.5",
"graphql-import": "^0.6.0",
"graphql-tag": "^2.9.2",
"graphql-tools": "3.1.1",
@@ -23,6 +27,6 @@
"devDependencies": {
"graphql-cli": "^2.16.5",
"npm-run-all": "4.1.3",
"prisma": "^1.16.0"
"prisma": "^1.16.4"
}
}
+74 -3
View File
@@ -1,5 +1,5 @@
# source: http://localhost:4466
# timestamp: Wed Sep 12 2018 08:41:57 GMT-0700 (Pacific Daylight Time)
# timestamp: Thu Sep 20 2018 16:52:44 GMT-0700 (Pacific Daylight Time)
type AggregateFBStatus {
count: Int!
@@ -1400,7 +1400,9 @@ type TeamProfile {
description: String
motto: String
avatar: String
banner: String
updatedAt: DateTime!
createdAt: DateTime!
}
"""A connection to a list of items."""
@@ -1417,6 +1419,7 @@ input TeamProfileCreateInput {
description: String
motto: String
avatar: String
banner: String
}
input TeamProfileCreateOneInput {
@@ -1439,19 +1442,23 @@ enum TeamProfileOrderByInput {
motto_DESC
avatar_ASC
avatar_DESC
banner_ASC
banner_DESC
updatedAt_ASC
updatedAt_DESC
id_ASC
id_DESC
createdAt_ASC
createdAt_DESC
id_ASC
id_DESC
}
type TeamProfilePreviousValues {
description: String
motto: String
avatar: String
banner: String
updatedAt: DateTime!
createdAt: DateTime!
}
type TeamProfileSubscriptionPayload {
@@ -1497,12 +1504,14 @@ input TeamProfileUpdateDataInput {
description: String
motto: String
avatar: String
banner: String
}
input TeamProfileUpdateInput {
description: String
motto: String
avatar: String
banner: String
}
input TeamProfileUpdateOneInput {
@@ -1647,6 +1656,46 @@ input TeamProfileWhereInput {
"""All values not ending with the given string."""
avatar_not_ends_with: String
banner: String
"""All values that are not equal to given value."""
banner_not: String
"""All values that are contained in given list."""
banner_in: [String!]
"""All values that are not contained in given list."""
banner_not_in: [String!]
"""All values less than the given value."""
banner_lt: String
"""All values less than or equal the given value."""
banner_lte: String
"""All values greater than the given value."""
banner_gt: String
"""All values greater than or equal the given value."""
banner_gte: String
"""All values containing the given string."""
banner_contains: String
"""All values not containing the given string."""
banner_not_contains: String
"""All values starting with the given string."""
banner_starts_with: String
"""All values not starting with the given string."""
banner_not_starts_with: String
"""All values ending with the given string."""
banner_ends_with: String
"""All values not ending with the given string."""
banner_not_ends_with: String
updatedAt: DateTime
"""All values that are not equal to given value."""
@@ -1669,6 +1718,28 @@ input TeamProfileWhereInput {
"""All values greater than or equal the given value."""
updatedAt_gte: DateTime
createdAt: DateTime
"""All values that are not equal to given value."""
createdAt_not: DateTime
"""All values that are contained in given list."""
createdAt_in: [DateTime!]
"""All values that are not contained in given list."""
createdAt_not_in: [DateTime!]
"""All values less than the given value."""
createdAt_lt: DateTime
"""All values less than or equal the given value."""
createdAt_lte: DateTime
"""All values greater than the given value."""
createdAt_gt: DateTime
"""All values greater than or equal the given value."""
createdAt_gte: DateTime
}
type TeamStatus {
@@ -15,6 +15,7 @@ const TEAMS_CONNECTIONS_FRAGMENT = gql`{
createdAt
profile {
avatar
banner
description
motto
updatedAt
+1
View File
@@ -13,6 +13,7 @@ const TEAMS_FRAGMENT = gql`{
createdAt
profile {
avatar
banner
description
motto
updatedAt
+42 -7
View File
@@ -7,12 +7,19 @@ const {
} = require('prisma-binding')
const { makeExecutableSchema } = require('graphql-tools')
const { importSchema } = require('graphql-import')
const parser = require('fast-xml-parser')
const checkJwt = require('./auth/middleware/jwt')
const { getMember } = require('./auth/middleware/getMember')
const { validateIdToken } = require('./auth/validateIdToken')
const { directiveResolvers } = require('./auth/authDirectives')
const Azure = require("@azure/storage-blob")
const { createSASQueryURL } = require('./storage/azure')
const azureAccount = process.env.AZURE_STORAGE_ACCOUNT
const azureKey = process.env.AZURE_STORAGE_ACCESS_KEY
const azureStorageUrl = process.env.AZURE_STORAGE_URL
const TEAMS_FRAGMENT = require('./graphql/TeamsFragment')
const TEAMS_CONNECTIONS_FRAGMENT = require('./graphql/TeamsConnectionsFragment')
@@ -43,8 +50,18 @@ const resolvers = {
return ctx.db.query.member({ where: { authId: arg.authId } }, info)
},
async currentMember(parent, args, ctx, info) {
console.log('currentMember: ', ctx.request.res.req.user)
console.log('currentMember: ', ctx.request.res.req.user, ctx.token)
const authId = ctx.request.res.req.user.sub
fetch('URL_GOES_HERE', {
method: 'post',
headers: new Headers({
'Authorization': 'Basic '+btoa('username:password'),
'Content-Type': 'application/x-www-form-urlencoded'
}),
body: 'A=1&B=2'
})
return ctx.db.query.member({ where: { authId } }, info)
},
teams(parent, args, ctx, info) {
@@ -57,7 +74,7 @@ const resolvers = {
return ctx.db.query.team({ where: { name: name } }, `{ name }`)
},
async teamsByOwner(parent, { ownerId }, ctx, info) {
console.log('teamsByOwner: ', ctx.user)
console.log('teamsByOwner: ', ctx)
return ctx.db.query.teams({where: { owner: ownerId }, orderBy:'updatedAt_DESC'}, TEAMS_FRAGMENT)
},
async owner(parent, args, ctx, info) {
@@ -100,8 +117,8 @@ const resolvers = {
return err
})
},
async updateTeamProfile(parent, { slug, owner, description, motto, avatar }, ctx, info) {
return ctx.db.mutation.updateTeam({data:{profile: {update: {description: description, motto: motto, avatar: avatar}}}, where:{slug: slug}}, TEAMS_FRAGMENT)
async updateTeamProfile(parent, { slug, owner, description, motto, avatar, banner }, ctx, info) {
return ctx.db.mutation.updateTeam({data:{profile: {update: {description: description, motto: motto, avatar: avatar, banner: banner}}}, where:{slug: slug}}, TEAMS_FRAGMENT)
.catch((err) => {
console.log('createTeam error: ', err)
return err
@@ -115,6 +132,11 @@ const resolvers = {
return error.message
})
})
},
async getAzureSAS(parent, { teamSlug }, ctx, info) {
const SASUrl = createSASQueryURL(teamSlug)
console.log('createSASQueryURL: ', SASUrl)
return SASUrl
}
}
}
@@ -148,7 +170,7 @@ server.express.use(
server.options.endpoint,
checkJwt,
function (err, req, res, next) {
console.log('checkJwt: ', err, req)
// console.log('checkJwt: ', err, req)
if (err) {
return res.status(201).send(err.message)
} else {
@@ -159,13 +181,26 @@ server.express.use(
server.express.post(server.options.endpoint, (req, res, done) => getUser(req, res, done, db))
const whitelist = [
let whitelist = [
'http://localhost:3000',
'http://localhost:3001',
'http://localhost:3002',
'http://localhost:4000',
'http://localhost:4002'
'http://localhost:4002',
'http://localhost:1337'
]
if(process.env.NODE_ENV === 'production'){
whitelist = [
'https://teams.advancedalgos.net',
'https://users.advancedalgos.net',
'https://users-api.advancedalgos.net',
'https://keyvault.advancedalgos.net',
'https://keyvault-api.advancedalgos.net',
'http://localhost:1337'
]
}
const corsOptionsDelegate = (req, callback) => {
var corsOptions
if (whitelist.indexOf(req.header('Origin')) !== -1) {
+2 -6
View File
@@ -19,13 +19,9 @@ type Query {
type Mutation {
authenticate(idToken: String!): Member
createTeam(name: String!, slug: String!, owner: String!): Team @isAuthenticated
updateTeamProfile(slug: String!, owner: String!, description: String, motto: String, avatar: String): Team @isAuthenticated
updateTeamProfile(slug: String!, owner: String!, description: String, motto: String, avatar: String, banner: String): Team @isAuthenticated
deleteTeam(slug: String!): Team @isAuthenticated @isOwner(type: "Team")
}
input MemberProfileInput {
authId: String!
alias: String!
getAzureSAS(teamSlug: String!):String
}
fragment MemberInfo on Member {
+191
View File
@@ -0,0 +1,191 @@
const Azure = require("@azure/storage-blob")
const azureAccount = process.env.AZURE_STORAGE_ACCOUNT
const azureKey = process.env.AZURE_STORAGE_ACCESS_KEY
const azureStorageUrl = process.env.AZURE_STORAGE_URL
/* Create Azure Storage pipeline
* @accountName: Azure Blob Storage account name (required) - Environment variable
* @accountKey: Azure Blob Storage storage key (required) - Environment variable
*/
const createStoragePipline = async (accountName, accountKey) => {
return Azure.StorageURL.newPipeline(
new Azure.SharedKeyCredential(accountName, accountKey)
)
}
/* Create Azure Storage Service URL
* @storageURL: URL for Azure Storage endpoint (required) - Environment variable
* @pipeline: Azure Storage Pipline (required) - created using createStoragePipeline()
*/
const createServiceURL = async (storageURL, pipeline) => {
return new Azure.ServiceURL(
storageURL,
pipeline
)
}
/* List containers
* @pipeline: Azure Storage Pipline (required) - created using createServiceURL
* @service_url: URL for Azure Storage endpoint (required) - Environment variable
*/
const listContainers = async (serviceURL) => {
let marker;
do {
const listContainersResponse = await serviceURL.listContainersSegment(
Azure.Aborter.None,
marker,
);
marker = listContainersResponse.marker;
for (const container of listContainersResponse.containerItems) {
console.log(`Container: ${container.name}`);
}
} while (marker);
}
/* Create containers
* @serviceURL: URL for Azure Storage endpoint (required) - created using createServiceURL
* @containerName: Container Name
* Returns: containerURL
*/
const createContainer = async (serviceURL, containerName) => {
const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName)
const createContainerResponse = await containerURL.create(Aborter.None)
console.log(
`Created container ${containerName} successfully`,
await createContainerResponse.requestId
)
return containerURL
}
/* Create containers
* @containerURL: continer URL (required) - created using createContainer
* @blobName: Blob Name
* Returns: blobURL
*/
const createBlob = async (containerURL, blobName) => {
const blobURL = Azure.BlobURL.fromContainerURL(containerURL, blobName)
console.log(`created blob successfully`, await blobURL)
return blobURL
}
/* Upload Blob
* @blobURL: blobURL (required) - created using createBlob
* @blobContent: Blob Content
* Returns: uploadBlobResponse
*/
const uploadBlob = async (blobURL, blobContent) => {
const blockBlobURL = Azure.BlockBlobURL.fromBlobURL(blobURL)
const uploadBlobResponse = await blockBlobURL.upload(
Azure.Aborter.None,
blobContent,
blobContent.length
);
console.log(`Upload block blob ${blobName} successfully`, await uploadBlobResponse)
return uploadBlobResponse
}
/* Download Blob
* @blobURL: blobURL (required) - created using createBlob
* @blobContent: Blob Content
* Returns: downloadBlockBlobResponse
*/
const downloadBlob = async (blobURL, blobContent) => {
const downloadBlockBlobResponse = await blobURL.download(Azure.Aborter.None, 0)
console.log(
"Downloaded blob content",
downloadBlockBlobResponse.readableStreamBody.read(content.length).toString()
)
console.log(`BlockBlobResponse: ${downloadBlockBlobResponse}`)
return downloadBlockBlobResponse
}
/* Delete Blob
* @blobURL: blobURL (required) - created using createBlob
* Returns: bool
*/
const deleteBlob = async (blobrURL) => {
await blobrURL.delete(Azure.Aborter.None);
console.log("deleted blob", blobrURL);
return true
}
/* Delete Container
* @containerURL: continer URL (required) - created using createContainer
* Returns: bool
*/
const deleteContainer = async (containerURL) => {
await containerURL.delete(Azure.Aborter.None);
console.log("deleted container", containerURL);
return true
}
const createSASQueryURL = async (containerName) => {
let today = new Date()
let week = new Date()
week.setDate(today.getDate() + 7)
// Create SharedKeyCredential and attach to pipline
const SKC = new Azure.SharedKeyCredential(azureAccount, azureKey)
const pipeline = Azure.StorageURL.newPipeline(SKC)
// Create container URL
const serviceURL = new Azure.ServiceURL(azureStorageUrl, pipeline)
const containerURL = Azure.ContainerURL.fromServiceURL(serviceURL, containerName)
//list container and check if already exists.
let marker
let containerCheck = null
do {
const listContainersResponse = await serviceURL.listContainersSegment(
Azure.Aborter.None,
marker,
)
// console.log(`ContainerCheck marker: `, listContainersResponse)
marker = listContainersResponse.marker;
for (const container of listContainersResponse.containerItems) {
// console.log(`ContainerCheck: ${container.name} | ${containerName} | ${marker}`)
if(container.name === containerName){
containerCheck = container.name
}
}
} while (marker)
// if container doesn't exist, create one
let newContainer
if(containerCheck === null){
newContainer = await containerURL.create(Azure.Aborter.None, { access: 'blob' })
}
console.log('createSASQueryURL container: ', containerURL, containerCheck, newContainer)
// Set permissions for service, resource types and containers
const SASContainerPerms = await Azure.AccountSASPermissions.parse('rwlacu')
const SASServicePerms = await Azure.AccountSASServices.parse('b')
const SASResourceTypes = await Azure.AccountSASResourceTypes.parse('co')
console.log('createSASQueryURL permissions: ', SASServicePerms, SASResourceTypes, SASContainerPerms)
// Generate SAS url
const SASQueryParameters = await Azure.generateBlobSASQueryParameters(
{
version: '2017-11-09',
protocol: 'https,http',
expiryTime: week,
permissions: 'rwlac',
containerName: containerName
}, SKC )
console.log('createSASQueryURL SASQueryParameters: ', containerURL.url, SASQueryParameters)
return SASQueryParameters
}
module.exports = {
createStoragePipline,
createServiceURL,
listContainers,
createContainer,
createBlob,
uploadBlob,
downloadBlob,
deleteBlob,
deleteContainer,
createSASQueryURL
}
+2
View File
@@ -9,3 +9,5 @@ AUTH0_AUDIENCE=<auth0-audience>
AUTH0_ISSUER=<auth0-issuer>
AUTH0_CLIENTID=<auth0-clientid>
AUTH0_CALLBACKURL=<auth0-callbackurl>
AZURE_STORAGE_CONNECTION_STRING=<azure-connections-string>
+1116 -404
View File
File diff suppressed because it is too large. Load diff
+12 -2
View File
@@ -18,13 +18,14 @@
"author": "Barry Low <bearcanrun@gmail.com>",
"license": "AGPL-3.0",
"devDependencies": {
"@babel/core": "^7.0.1",
"@babel/core": "^7.1.2",
"@babel/plugin-proposal-class-properties": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@babel/preset-react": "^7.0.0",
"autoprefixer": "^8.6.5",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^9.0.0",
"babel-loader": "^8.0.2",
"babel-loader": "^7.1.5",
"babel-minify-webpack-plugin": "^0.3.1",
"babel-plugin-dynamic-import-node": "^1.2.0",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
@@ -67,6 +68,8 @@
"workbox-cli": "^3.4.1"
},
"dependencies": {
"@advancedalgos/web-components": "0.0.5",
"@azure/storage-blob": "^10.0.0-preview",
"@material-ui/core": "^3.0.3",
"@material-ui/icons": "^3.0.1",
"apollo-cache-inmemory": "^1.2.9",
@@ -78,7 +81,10 @@
"apollo-link-ws": "^1.0.8",
"apollo-utilities": "^1.0.20",
"auth0-lock": "^11.9.0",
"azure-storage": "^2.10.1",
"babel-polyfill": "^6.26.0",
"blob-util": "^2.0.2",
"browser-image-resizer": "^1.2.0",
"classnames": "^2.2.6",
"cross-fetch": "^2.2.2",
"dotenv-webpack": "^1.5.7",
@@ -88,8 +94,12 @@
"react": "^16.5.0",
"react-apollo": "^2.1.11",
"react-dom": "^16.5.0",
"react-dropzone": "^5.1.0",
"react-image-crop": "^5.0.0",
"react-image-cropper": "^1.3.0",
"react-router-dom": "^4.3.1",
"recompose": "^0.30.0",
"sharp": "^0.20.8",
"subscriptions-transport-ws": "^0.9.14"
},
"standard": {
+6
View File
@@ -64,6 +64,7 @@ wsClient.onReconnected(() => {
})
const httpLink = new HttpLink({ uri: graphqlEndpoint })
const httpUserLink = new HttpLink({ uri: 'https://users-api.advancedalgos.net/graphql' })
const link = split(
({ query }) => {
@@ -134,6 +135,11 @@ export const client = new ApolloClient({
connectToDevTools: true
})
export const UserClient = new ApolloClient({
link: ApolloLink.from([authRetryLink, authLink, httpUserLink]),
cache
})
export const auth = new Auth(
result => console.log('auth result', result),
client
@@ -0,0 +1,25 @@
/* eslint-disable no-unused-vars */
import gql from 'graphql-tag'
export const USER_BY_AUTHID = gql`
query($authId: String){
userByAuthId (authId: $authId){
id
alias
firstName
middleName
lastName
bio
email
emailVerified
isDeveloper
isDataAnalyst
isTrader
role {
id
}
}
}
`
export default USER_BY_AUTHID
+2 -1
View File
@@ -1,3 +1,4 @@
import { GetCurrentMember } from './GetCurrentMemberQuery'
import { USER_BY_AUTHID } from './GetUserByAuthIDQuery'
export { GetCurrentMember }
export { GetCurrentMember, USER_BY_AUTHID }
@@ -18,6 +18,7 @@ export const GET_ALL_TEAMS_QUERY = gql`
createdAt
profile {
avatar
banner
description
motto
updatedAt
@@ -0,0 +1,10 @@
/* eslint-disable no-unused-vars */
import gql from 'graphql-tag'
export const GET_AZURE_SAS = gql`
mutation getAzureSAS($teamSlug: String!) {
getAzureSAS(teamSlug: $teamSlug)
}
`
export default GET_AZURE_SAS
@@ -16,6 +16,7 @@ export const GET_TEAMS_BY_OWNER = gql`
createdAt
profile {
avatar
banner
description
motto
updatedAt
+1
View File
@@ -15,6 +15,7 @@ export const TEAMS_FRAGMENT = gql`
createdAt
profile {
avatar
banner
description
motto
updatedAt
@@ -3,16 +3,20 @@ import gql from 'graphql-tag'
const UPDATE_TEAM_PROFILE = gql`
mutation UpdateTeamProfileMutation(
$slug: String!
$owner: String!
$description: String
$motto: String
$slug: String!,
$owner: String!,
$description: String,
$motto: String,
$avatar: String,
$banner: String
) {
updateTeamProfile(
slug: $slug
owner: $owner
description: $description
slug: $slug,
owner: $owner,
description: $description,
motto: $motto
avatar: $avatar,
banner: $banner
) {
id
name
@@ -26,6 +30,7 @@ const UPDATE_TEAM_PROFILE = gql`
createdAt
profile {
avatar
banner
description
motto
updatedAt
-45
View File
@@ -1,45 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import Typography from '@material-ui/core/Typography'
import { withStyles } from '@material-ui/core/styles'
import Card from '@material-ui/core/Card'
import CardContent from '@material-ui/core/CardContent'
const styles = theme => ({
card: {
display: 'flex',
width: '100%',
margin: '1.5em',
padding: '3em'
},
cardDetails: {
display: 'flex',
flex: 1
},
cardContent: {
flex: 1
}
})
export const MessageCard = ({ classes, message, children }) => (
<Card className={classes.card}>
<div className={classes.cardDetails}>
<CardContent className={classes.cardContent}>
<Typography variant='headline' align='center' gutterBottom>
{message}
</Typography>
{children}
</CardContent>
</div>
</Card>
)
MessageCard.propTypes = {
children: PropTypes.node,
classes: PropTypes.object.isRequired,
message: PropTypes.string
}
export default withStyles(styles)(MessageCard)
-3
View File
@@ -1,3 +0,0 @@
import MessageCard from './MessageCard'
export { MessageCard }
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types'
import Typography from '@material-ui/core/Typography'
import { withStyles } from '@material-ui/core/styles'
import { MessageCard } from '../common/'
import { MessageCard } from '@advancedalgos/web-components'
const styles = theme => ({
tableContainer: {
+1 -1
View File
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types'
import Typography from '@material-ui/core/Typography'
import { withStyles } from '@material-ui/core/styles'
import { MessageCard } from '../common/'
import { MessageCard } from '@advancedalgos/web-components'
const styles = theme => ({
tableContainer: {
@@ -11,7 +11,7 @@ import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
import DashTeamItem from './DashTeamItem'
import CreateTeamDialog from './CreateTeamDialog'
import { MessageCard } from '../../common/'
import { MessageCard } from '@advancedalgos/web-components'
import { isDefined, isString } from '../../../utils/js-helpers'
import { getItem } from '../../../utils/local-storage'
@@ -35,13 +35,15 @@ const styles = theme => ({
}
})
const placeholder = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22288%22%20height%3D%22225%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20288%20225%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_164edaf95ee%22%3E%3Crect%20width%3D%22288%22%20height%3D%22225%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.32500076293945%22%20y%3D%22118.8%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E' // eslint-disable-line max-len
export const DashTeamItem = ({ classes, team }) => (
<Grid item>
<Card className={classes.card}>
<div className={classes.cardDetails}>
<CardMedia
className={classes.cardMedia}
image='data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22288%22%20height%3D%22225%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20288%20225%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_164edaf95ee%22%3E%3Crect%20width%3D%22288%22%20height%3D%22225%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.32500076293945%22%20y%3D%22118.8%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E' // eslint-disable-line max-len
image={team.profile !== null && team.profile.avatar !== undefined && team.profile.avatar !== null ? team.profile.avatar : placeholder}
title='Image title'
/>
<CardContent className={classes.cardContent}>
@@ -5,10 +5,11 @@ import { withStyles } from '@material-ui/core/styles'
import Button from '@material-ui/core/Button'
import DetailsIcon from '@material-ui/icons/Details'
import Dialog from '@material-ui/core/Dialog'
import DialogActions from '@material-ui/core/DialogActions'
import DialogContent from '@material-ui/core/DialogContent'
import DialogTitle from '@material-ui/core/DialogTitle'
import Typography from '@material-ui/core/Typography'
import Card from '@material-ui/core/Card'
import CardContent from '@material-ui/core/CardContent'
import CardActions from '@material-ui/core/CardActions'
import CardMedia from '@material-ui/core/CardMedia'
const styles = theme => ({
dialogContainer: {
@@ -18,6 +19,33 @@ const styles = theme => ({
},
buttonRight: {
justifyContent: 'flex-end'
},
cardGrid: {
padding: `${theme.spacing.unit * 8}px 0`
},
card: {
display: 'flex',
width: '100%'
},
cardDetails: {
display: 'flex',
flex: 1
},
cardContent: {
flex: 1
},
cardAvatarMedia: {
flex: 1,
width: 100,
height: 100,
maxWidth: 100,
justifyContent: 'flex-start'
},
cardBannerMedia: {
flex: 1,
width: 600,
height: 150,
justifyContent: 'flex-start'
}
})
@@ -35,7 +63,20 @@ export class ManageTeamDetails extends Component {
render () {
console.log(this.props.team)
const { classes } = this.props
const { name, members, profile, createdAt } = this.props.team
let avatar
let banner
if (profile.avatar !== undefined && profile.avatar !== 'a') {
avatar = profile.avatar
} else {
avatar = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22288%22%20height%3D%22225%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20288%20225%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_164edaf95ee%22%3E%3Crect%20width%3D%22288%22%20height%3D%22225%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.32500076293945%22%20y%3D%22118.8%22%3EAvatar%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'
}
if (profile.banner !== undefined && profile.banner !== 'a') {
banner = profile.banner
} else {
banner = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22800%22%20height%3D%22200%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Asvg%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23banner_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%3E%3Ctitle%3EBanner%20Placeholder%3C%2Ftitle%3E%3Crect%20stroke%3D%22null%22%20id%3D%22svg_1%22%20fill%3D%22%2355595c%22%20height%3D%22200%22%20width%3D%22800%22%2F%3E%3Cg%20stroke%3D%22null%22%20id%3D%22banner_164edaf95ee%22%3E%3Ctext%20stroke%3D%22null%22%20id%3D%22svg_3%22%20y%3D%22106.5%22%20x%3D%22367.73438%22%3EBanner%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'
}
return (
<div>
<Button
@@ -51,51 +92,62 @@ export class ManageTeamDetails extends Component {
onClose={this.handleClose}
aria-labelledby='form-dialog-title'
>
<div classes={this.props.classes.dialogContainer}>
<DialogTitle id='form-dialog-title'>
{name} Team Details
</DialogTitle>
<DialogContent>
<Typography
variant='display3'
align='center'
color='textPrimary'
gutterBottom
>
{name}
</Typography>
<Typography variant='subheading' color='textSecondary'>
{createdAt}
</Typography>
<Typography variant='subheading' color='textSecondary'>
Motto: {profile.motto}
</Typography>
<Typography variant='subheading' color='textSecondary'>
Description: {profile.description}
</Typography>
<Typography variant='subheading' paragraph gutterBottom>
Members: {members.length}
</Typography>
<Typography variant='subheading' color='primary'>
Team Admin:&nbsp;
{members.map(member => {
if (member.role === 'OWNER' || member.role === 'ADMIN') {
if (
member.member !== null &&
<div classes={classes.dialogContainer}>
<Card className={classes.card}>
<CardContent>
<Typography variant='title' id='form-dialog-title'>
{name} Team Details
</Typography>
<CardMedia
className={classes.cardBannerMedia}
image={banner}
title={`${name} ${banner}`}
/>
<CardMedia
className={classes.cardAvatarMedia}
image={avatar}
title={`${name} ${avatar}`}
/>
<Typography
variant='display3'
align='center'
color='textPrimary'
gutterBottom
>
{name}
</Typography>
<Typography variant='subheading' color='textSecondary'>
{createdAt}
</Typography>
<Typography variant='subheading' color='textSecondary'>
Motto: {profile.motto}
</Typography>
<Typography variant='subheading' color='textSecondary'>
Description: {profile.description}
</Typography>
<Typography variant='subheading' paragraph gutterBottom>
Members: {members.length}
</Typography>
<Typography variant='subheading' color='primary'>
Team Admin:&nbsp;
{members.map(member => {
if (member.role === 'OWNER' || member.role === 'ADMIN') {
if (member.member !== null &&
member.member.alias !== undefined &&
member.member.alias !== null
) {
return member.member.alias
) {
return member.member.alias
}
}
}
})}
</Typography>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClose} color='primary'>
Close
</Button>
</DialogActions>
})}
</Typography>
<CardActions>
<Button onClick={this.handleClose} color='primary'>
Close
</Button>
</CardActions>
</CardContent>
</Card>
</div>
</Dialog>
</div>
@@ -13,13 +13,15 @@ import DialogContentText from '@material-ui/core/DialogContentText'
import DialogTitle from '@material-ui/core/DialogTitle'
import Typography from '@material-ui/core/Typography'
import { getItem } from '../../../utils/local-storage'
import { MessageCard, ImageUpload } from '@advancedalgos/web-components'
import UPDATE_TEAM_PROFILE from '../../../graphql/teams/UpdateTeamProfileMutation'
import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
import { checkGraphQLError } from '../../../utils/graphql-errors'
import GET_AZURE_SAS from '../../../graphql/teams/GetAzureSASMutation'
const styles = theme => ({
dialogContainer: {
display: 'block',
@@ -39,26 +41,35 @@ export class ManageTeamEdit extends Component {
this.handleClose = this.handleClose.bind(this)
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
this.handleAvatar = this.handleAvatar.bind(this)
this.handleBanner = this.handleBanner.bind(this)
console.log('ManageTeamEdit', props.team)
const motto = props.team.profile.motto || ''
const description = props.team.profile.description || ''
const avatar = props.team.profile.avatar || ''
const banner = props.team.profile.banner || ''
this.authId = props.authId
this.state = {
open: false,
motto: motto,
description: description
description: description,
avatar: avatar,
banner: banner
}
}
render () {
console.log(this.props, this.props.slug)
const { classes, team, authId } = this.props
console.log('ManageTeamEdit ', this.props, this.props.slug, this.props.team)
const { classes, team } = this.props
return (
<Mutation
mutation={UPDATE_TEAM_PROFILE}
refetchQueries={[
{
query: GET_TEAMS_BY_OWNER,
variables: { authId }
variables: { authId: this.authId }
}
]}
>
@@ -101,6 +112,77 @@ export class ManageTeamEdit extends Component {
Edit Team Details
</DialogTitle>
<DialogContent>
<Mutation mutation={GET_AZURE_SAS} >
{(getAzureSAS, { loading, error, data }) => {
console.log('getAzureSAS: ', loading, error, data, team.profile)
const AzureStorageUrl = process.env.AZURE_STORAGE_URL
const containerName = team.slug
let AzureSASURL
if (!loading && data !== undefined) {
AzureSASURL = data.getAzureSAS
} else {
getAzureSAS({ variables: { teamSlug: containerName } })
}
let avatar = null
if (this.state.avatar !== null) avatar = this.state.avatar
if (team.profile !== null && team.profile.avatar !== undefined && team.profile.avatar !== null) avatar = team.profile.avatar
let banner = null
if (this.state.banner !== null) banner = this.state.banner
if (team.profile !== null && team.profile.banner !== undefined && team.profile.banner !== null) banner = team.profile.banner
console.log('team images: ', avatar, banner)
if (loading || data === undefined) {
return (<MessageCard message='Loading...' />)
} else {
return (
<React.Fragment>
<ImageUpload
key='banner'
handleUrl={this.handleBanner}
fileName={`${team.slug}-banner.jpg`}
containerName={containerName}
existingImage={banner}
cropContainer={{ x: 10, y: 10, width: 800, height: 200 }}
cropPreviewBox={{ width: 650, height: 200 }}
saveImageConfig={{
quality: 0.6,
maxWidth: 800,
maxHeight: 200,
autoRotate: true,
mimeType: 'image/jpeg'
}}
AzureStorageUrl={AzureStorageUrl}
AzureSASURL={AzureSASURL}
cropRatio={4}
debug
/>
<ImageUpload
key='avatar'
handleUrl={this.handleAvatar}
fileName={`${team.slug}-avatar.jpg`}
containerName={containerName}
existingImage={avatar}
cropContainer={{ x: 10, y: 10, width: 200, height: 200 }}
cropPreviewBox={{ width: 350, height: 350 }}
saveImageConfig={{
quality: 0.6,
maxWidth: 200,
maxHeight: 200,
autoRotate: true,
mimeType: 'image/jpeg'
}}
AzureStorageUrl={AzureStorageUrl}
AzureSASURL={AzureSASURL}
cropRatio={1}
debug
/>
</React.Fragment>
)
}
}}
</Mutation>
<TextField
autoFocus
margin='dense'
@@ -178,17 +260,28 @@ export class ManageTeamEdit extends Component {
}
}
handleAvatar (avatarUrl) {
console.log('handleAvatar: ', avatarUrl)
this.setState({ avatar: `${avatarUrl}?${Math.random()}` })
}
handleBanner (bannerUrl) {
console.log('handleBanner: ', bannerUrl)
this.setState({ banner: `${bannerUrl}?${Math.random()}` })
}
async handleSubmit (e, updateTeamProfile, slug) {
console.log('handleSubmit: ', this.state)
e.preventDefault()
const currentUser = await getItem('user')
let authId = JSON.parse(currentUser)
authId = authId.authId
await updateTeamProfile({
variables: {
slug,
owner: authId,
owner: this.authId,
description: this.state.description,
motto: this.state.motto
motto: this.state.motto,
avatar: this.state.avatar,
banner: this.state.banner
}
})
this.setState({ description: '', motto: '', open: false })
@@ -198,8 +291,8 @@ export class ManageTeamEdit extends Component {
ManageTeamEdit.propTypes = {
classes: PropTypes.object.isRequired,
slug: PropTypes.string.isRequired,
authId: PropTypes.string,
team: PropTypes.object
team: PropTypes.object,
authId: PropTypes.string.isRequired
}
export default withStyles(styles)(ManageTeamEdit)
@@ -12,32 +12,41 @@ import ManageTeamDetails from './ManageTeamDetails'
import ManageTeamDelete from './ManageTeamDelete'
import ManageTeamEdit from './ManageTeamEdit'
export const ManageTeamsItem = ({ classes, team, authId }) => (
<Grid item xs={12}>
<Card className={classes.card}>
<div className={classes.cardDetails}>
<CardMedia
className={classes.cardMedia}
image='data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22288%22%20height%3D%22225%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20288%20225%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_164edaf95ee%22%3E%3Crect%20width%3D%22288%22%20height%3D%22225%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.32500076293945%22%20y%3D%22118.8%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E' // eslint-disable-line max-len
title='Image title'
/>
<CardContent className={classes.cardContent}>
<Typography gutterBottom variant='headline' component='h2'>
{team.name}
</Typography>
<Typography variant='caption' color='textSecondary'>
{team.createdAt} | Members: {team.members.length}
</Typography>
</CardContent>
<CardActions>
<ManageTeamDetails team={team} />
<ManageTeamEdit slug={team.slug} authId={authId} team={team} />
<ManageTeamDelete slug={team.slug} authId={authId} />
</CardActions>
</div>
</Card>
</Grid>
)
export const ManageTeamsItem = ({ classes, team, authId }) => {
console.log('ManageTeamsItem', team, team.profile, team.profile.avatar)
let avatar
if (team.profile.avatar !== undefined && team.profile.avatar !== 'a') {
avatar = team.profile.avatar
} else {
avatar = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22288%22%20height%3D%22225%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20288%20225%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_164edaf95ee%22%3E%3Crect%20width%3D%22288%22%20height%3D%22225%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.32500076293945%22%20y%3D%22118.8%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'
}
return (
<Grid item xs={12}>
<Card className={classes.card}>
<div className={classes.cardDetails}>
<CardMedia
className={classes.cardMedia}
image={avatar}
title={team.name}
/>
<CardContent className={classes.cardContent}>
<Typography gutterBottom variant='headline' component='h2'>
{team.name}
</Typography>
<Typography variant='caption' color='textSecondary'>
{team.createdAt} | Members: {team.members.length}
</Typography>
</CardContent>
<CardActions>
<ManageTeamDetails team={team} />
<ManageTeamEdit slug={team.slug} authId={authId} team={team} />
<ManageTeamDelete slug={team.slug} authId={authId} />
</CardActions>
</div>
</Card>
</Grid>
)
}
ManageTeamsItem.propTypes = {
classes: PropTypes.object.isRequired,
@@ -4,6 +4,7 @@ import { Query } from 'react-apollo'
import { withStateHandlers, lifecycle, compose } from 'recompose'
import Grid from '@material-ui/core/Grid'
import { MessageCard } from '@advancedalgos/web-components'
import { withStyles } from '@material-ui/core/styles'
import { isDefined, isString } from '../../../utils/js-helpers'
@@ -13,7 +14,6 @@ import GET_TEAMS_BY_OWNER from '../../../graphql/teams/GetTeamsByOwnerQuery'
import ManageTeamsItem from './ManageTeamsItem'
import CreateTeamDialog from './CreateTeamDialog'
import { MessageCard } from '../../common/'
const styles = theme => ({
heroContent: {
+1 -1
View File
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types'
import Typography from '@material-ui/core/Typography'
import { withStyles } from '@material-ui/core/styles'
import { MessageCard } from '../common/'
import { MessageCard } from '@advancedalgos/web-components'
const styles = theme => ({
tableContainer: {
+40 -9
View File
@@ -1,17 +1,22 @@
import React from 'react'
import PropTypes from 'prop-types'
import { graphql } from 'react-apollo'
import { Query } from 'react-apollo'
import LoggedInMenu from './LoggedInMenu'
import { GetCurrentMember } from '../../graphql/members'
import { UserClient } from '../../App'
import { USER_BY_AUTHID } from '../../graphql/members'
import { isDefined } from '../../utils/js-helpers'
export const LoggedIn = props => {
let { data, user, auth } = props
console.log('LoggedIn :', data, user)
console.log('LoggedIn :', data, user, auth)
let displayName = 'No Display Name'
let authId = null
if (isDefined(user.authId)) {
authId = user.authId
}
if (isDefined(user.alias)) {
displayName = user.alias
@@ -29,12 +34,38 @@ export const LoggedIn = props => {
displayName = user.firstName + ' ' + user.lastName
}
if (authId === null) {
return (
<div>Loading...</div>
)
}
return (
<div>
<p>
<LoggedInMenu menuLabel={displayName} auth={auth} />
</p>
</div>
<Query
query={USER_BY_AUTHID}
fetchPolicy='network-only'
variables={{ authId }}
client={UserClient}
>
{({ loading, error, data }) => {
console.log('USER_BY_AUTHID: ', loading, error, data)
if (loading) {
return <div>Loading...</div>
}
if (error) {
error.graphQLErrors.map(({ message }, i) => {
return <div>{message}</div>
})
}
return (
<p>
<LoggedInMenu menuLabel={displayName} auth={auth} user={data.userByAuthId} />
</p>
)
}}
</Query>
)
}
@@ -44,4 +75,4 @@ LoggedIn.propTypes = {
auth: PropTypes.object.isRequired
}
export default graphql(GetCurrentMember)(LoggedIn) // This binds the querty to the component
export default LoggedIn
+36 -6
View File
@@ -1,16 +1,29 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { withStyles } from '@material-ui/core/styles'
import Button from '@material-ui/core/Button'
import Menu from '@material-ui/core/Menu'
import MenuItem from '@material-ui/core/MenuItem'
import Drawer from '@material-ui/core/Drawer'
import { Link } from 'react-router-dom'
import ProfileIcon from '@material-ui/icons/Person'
import LogoutIcon from '@material-ui/icons/DirectionsWalk'
const UserLink = props => <Link to='/user' {...props} />
import UserProfile from './Profile'
const LogoutLink = props => <Link to='/' {...props} />
const styles = {
drawer: {
width: 250
},
fullList: {
width: 'auto'
}
}
class LoggedInUserMenu extends Component {
constructor (props) {
super(props)
@@ -18,14 +31,16 @@ class LoggedInUserMenu extends Component {
this.handleMenu = this.handleMenu.bind(this)
this.handleClose = this.handleClose.bind(this)
this.handleLogout = this.handleLogout.bind(this)
this.toggleDrawer = this.toggleDrawer.bind(this)
this.state = {
menu: null
menu: null,
open: false
}
}
render () {
const { menuLabel } = this.props
const { menuLabel, user, classes } = this.props
return (
<React.Fragment>
<Button
@@ -42,7 +57,7 @@ class LoggedInUserMenu extends Component {
open={Boolean(this.state.menu)}
onClose={this.handleClose}
>
<MenuItem onClick={this.handleClose} component={UserLink}>
<MenuItem onClick={this.toggleDrawer}>
<ProfileIcon />
<div>Profile</div>
</MenuItem>
@@ -51,6 +66,15 @@ class LoggedInUserMenu extends Component {
<div>Logout</div>
</MenuItem>
</Menu>
<Drawer anchor='right' open={this.state.open} onClose={this.toggleDrawer} className={classes.drawer}>
<div
tabIndex={0}
role='button'
onClick={this.toggleDrawer}
>
<UserProfile user={user} toggleDrawer={this.toggleDrawer} />
</div>
</Drawer>
</React.Fragment>
)
}
@@ -67,11 +91,17 @@ class LoggedInUserMenu extends Component {
this.props.auth.logout()
this.setState({ menu: null })
}
toggleDrawer () {
this.setState({ open: !this.state.open })
}
}
LoggedInUserMenu.propTypes = {
classes: PropTypes.object.isRequired,
menuLabel: PropTypes.string.isRequired,
auth: PropTypes.object.isRequired
auth: PropTypes.object.isRequired,
user: PropTypes.object
}
export default LoggedInUserMenu
export default withStyles(styles)(LoggedInUserMenu)
+94
View File
@@ -0,0 +1,94 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
// Materia UI
import { withStyles } from '@material-ui/core/styles'
import Button from '@material-ui/core/Button'
import Grid from '@material-ui/core/Grid'
import Card from '@material-ui/core/Card'
import CardContent from '@material-ui/core/CardContent'
import CardMedia from '@material-ui/core/CardMedia'
import Typography from '@material-ui/core/Typography'
import Divider from '@material-ui/core/Divider'
// Images
const styles = theme => ({
root: {
flexGrow: 1,
padding: 60,
margin: 2
},
card: {
maxWidth: 240,
minWidth: 240,
paddingTop: '30'
},
media: {
paddingTop: '56.25%', // 16:9,
marginTop: '30',
width: 100,
height: 100,
maxWidth: 100
},
grid: {
paddingTop: '30',
marginTop: '30'
},
typography: {
width: '100%',
marginTop: 20,
marginBottom: 20
}
})
class UserProfile extends Component {
render () {
const { classes, user, toggleDrawer } = this.props
return (
<Grid container justify='center' spacing={24}>
<Grid key={user.id} item>
<Card className={classes.card}>
<CardContent>
<Button
onClick={toggleDrawer}
color='inherit'
>
Close Profile
</Button>
<CardMedia
className={classes.media}
image='data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22288%22%20height%3D%22225%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20288%20225%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_164edaf95ee%22%3E%3Crect%20width%3D%22288%22%20height%3D%22225%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.32500076293945%22%20y%3D%22118.8%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'
title='User Profile'
/>
<Typography className={classes.typography} gutterBottom variant='headline' component='h2'>
{ user.firstName } { user.lastName } ( {user.alias} )
</Typography>
<Divider />
<Typography className={classes.typography} align='left' gutterBottom variant='subheading' component='h2'>
{ user.role.name }
</Typography>
<Divider />
<Typography className={classes.typography} component='p'>
{ user.bio }
</Typography>
</CardContent>
</Card>
</Grid>
</Grid>
)
}
}
UserProfile.propTypes = {
classes: PropTypes.object.isRequired,
user: PropTypes.object,
toggleDrawer: PropTypes.func
}
export default withStyles(styles)(UserProfile)
@@ -42,49 +42,68 @@ const styles = theme => ({
maxWidth: 600,
margin: '0 auto',
padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px`
},
banner: {
maxWidth: '100%',
height: 'auto',
margin: '0 auto'
},
avatar: {
maxWidth: 100,
height: 100,
margin: '0 1em 1em 0',
float: 'left'
}
})
const TeamsDetails = ({ classes, team }) => (
<React.Fragment>
<CssBaseline />
<main className={classes.layout}>
<Paper className={classes.paper}>
<div className={classes.heroContent}>
<Link to='/teams'>&larr; Back to all teams</Link>
<Typography
variant='display3'
align='center'
color='textPrimary'
gutterBottom
>
{team.name}
</Typography>
<Typography variant='subheading' color='textSecondary'>
{team.createdAt}
</Typography>
<Typography variant='subheading' color='textSecondary'>
Motto: {team.profile.motto}
</Typography>
<Typography variant='subheading' color='textSecondary'>
Description: {team.profile.description}
</Typography>
<Typography variant='subheading' paragraph gutterBottom>
Members: {team.members.length}
</Typography>
<Typography variant='subheading' color='primary'>
Team Admin:&nbsp;
{team.members.map(member => {
if (member.role === 'OWNER' || member.role === 'ADMIN') {
return member.member.alias
}
})}
</Typography>
</div>
</Paper>
</main>
</React.Fragment>
)
const TeamsDetails = ({ classes, team }) => {
let avatar
if (team.profile.avatar !== undefined && team.profile.avatar !== 'a') {
avatar = team.profile.avatar
} else {
avatar = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22288%22%20height%3D%22225%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20288%20225%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_164edaf95ee%22%3E%3Crect%20width%3D%22288%22%20height%3D%22225%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.32500076293945%22%20y%3D%22118.8%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'
}
let banner
if (team.profile.banner !== undefined && team.profile.banner !== 'a') {
banner = team.profile.banner
} else {
banner = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22288%22%20height%3D%22225%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20288%20225%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_164edaf95ee%22%3E%3Crect%20width%3D%22288%22%20height%3D%22225%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.32500076293945%22%20y%3D%22118.8%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'
}
return (
<React.Fragment>
<CssBaseline />
<main className={classes.layout}>
<Paper className={classes.paper}>
<div className={classes.heroContent}>
<Link to='/teams'>&larr; Back to all teams</Link>
<img src={banner} alt={team.name} className={classes.banner} />
<img src={avatar} alt={team.name} className={classes.avatar} />
<Typography
variant='display3'
align='center'
color='textPrimary'
gutterBottom
>
{team.name}
</Typography>
<Typography variant='subheading' color='textSecondary'>
{team.createdAt}
</Typography>
<Typography variant='subheading' color='textSecondary'>
Motto: {team.profile.motto}
</Typography>
<Typography variant='subheading' color='textSecondary'>
Description: {team.profile.description}
</Typography>
<Typography variant='subheading' paragraph gutterBottom>
Members: {team.members.length}
</Typography>
</div>
</Paper>
</main>
</React.Fragment>
)
}
TeamsDetails.propTypes = {
classes: PropTypes.object.isRequired,
team: PropTypes.object.isRequired
+48 -34
View File
@@ -12,40 +12,54 @@ import Typography from '@material-ui/core/Typography'
import { Link } from 'react-router-dom'
export const TeamsItem = ({ classes, team }) => (
<Grid item sm={6} md={4} lg={3}>
<Card className={classes.card}>
<CardActionArea>
<CardMedia
className={classes.cardMedia}
image='data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22288%22%20height%3D%22225%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20288%20225%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_164edaf95ee%22%3E%3Crect%20width%3D%22288%22%20height%3D%22225%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.32500076293945%22%20y%3D%22118.8%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E' // eslint-disable-line max-len
title='Image title'
/>
<CardContent className={classes.cardContent}>
<Typography gutterBottom variant='headline' component='h2'>
{team.name}
</Typography>
<Typography variant='caption' color='textSecondary'>
{team.createdAt}
</Typography>
<Typography variant='caption' paragraph gutterBottom>
Members: 1
</Typography>
<Typography variant='subheading' color='primary'>
Now recruiting!
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Link to={`/teams/${team.slug}`}>
<Button size='small' color='primary' className={classes.buttonRight}>
Details
</Button>
</Link>
</CardActions>
</Card>
</Grid>
)
export const TeamsItem = ({ classes, team }) => {
/* let avatar
if (team.profile.avatar !== undefined && team.profile.avatar !== 'a') {
avatar = team.profile.avatar
} else {
avatar = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22288%22%20height%3D%22225%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20288%20225%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_164edaf95ee%22%3E%3Crect%20width%3D%22288%22%20height%3D%22225%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.32500076293945%22%20y%3D%22118.8%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'
} */
let banner
if (team.profile.banner !== undefined && team.profile.banner !== null) {
banner = team.profile.banner
} else {
banner = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22288%22%20height%3D%22225%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20288%20225%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_164edaf95ee%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A14pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_164edaf95ee%22%3E%3Crect%20width%3D%22288%22%20height%3D%22225%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.32500076293945%22%20y%3D%22118.8%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'
}
return (
<Grid item sm={6} md={4} lg={3}>
<Card className={classes.card}>
<CardActionArea>
<CardMedia
className={classes.cardMedia}
image={banner}
title={team.name}
/>
<CardContent className={classes.cardContent}>
<Typography gutterBottom variant='headline' component='h2'>
{team.name}
</Typography>
<Typography variant='caption' color='textSecondary'>
{team.createdAt}
</Typography>
<Typography variant='caption' paragraph gutterBottom>
Members: 1
</Typography>
<Typography variant='subheading' color='primary'>
Now recruiting!
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Link to={`/teams/${team.slug}`}>
<Button size='small' color='primary' className={classes.buttonRight}>
Details
</Button>
</Link>
</CardActions>
</Card>
</Grid>
)
}
TeamsItem.propTypes = {
classes: PropTypes.object.isRequired,
+2 -1
View File
@@ -40,7 +40,8 @@ module.exports = merge(commonConfig, {
loader: 'style-loader!css-loader!postcss-loader!sass-loader'
}
]
}
},
target: 'web'
})
module.exports.serve = {
+4 -3
View File
@@ -61,11 +61,12 @@ module.exports = merge(commonConfig, {
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{loader: 'css-loader', options: { importLoaders: 2 }},
{ loader: 'css-loader', options: { importLoaders: 2 } },
'postcss-loader',
{loader: 'sass-loader'}
{ loader: 'sass-loader' }
]
}
]
}
},
target: 'web'
})