Testing new email...

This commit is contained in:
Atridad Lahiji 2023-06-07 22:21:02 -06:00
parent 9af6d08c91
commit e2e2253a6a
No known key found for this signature in database
9 changed files with 373 additions and 52 deletions

View file

@ -21,9 +21,7 @@ ABLY_PRIVATE_KEY=""
NEXT_PUBLIC_ABLY_PUBLIC_KEY=""
# Email
JMAP_TOKEN=""
JMAP_USERNAME=""
JMAP_HOSTNAME=""
RESEND_API_KEY=""
# Misc
APP_ENV=""

View file

@ -33,6 +33,7 @@
"react-dom": "18.2.0",
"react-icons": "^4.9.0",
"redicache-ts": "^0.1.1",
"resend": "^0.15.1",
"sharp": "^0.32.1",
"superjson": "1.12.3",
"zod": "^3.21.4"

285
pnpm-lock.yaml generated
View file

@ -65,6 +65,9 @@ dependencies:
redicache-ts:
specifier: ^0.1.1
version: 0.1.1
resend:
specifier: ^0.15.1
version: 0.15.1
sharp:
specifier: ^0.32.1
version: 0.32.1
@ -1604,6 +1607,16 @@ packages:
resolution: {integrity: sha512-FTaOCGs0LL0OW68juZlGxFtYviZa4xdQj/rQEdat2txw0s3Vu/saAPKjNVXfIgUsGXmQ72HPgNr6935/P8FNAA==}
requiresBuild: true
/@react-email/render@0.0.7:
resolution: {integrity: sha512-hMMhxk6TpOcDC5qnKzXPVJoVGEwfm+U5bGOPH+MyTTlx0F02RLQygcATBKsbP7aI/mvkmBAZoFbgPIHop7ovug==}
engines: {node: '>=16.0.0'}
dependencies:
html-to-text: 9.0.3
pretty: 2.0.0
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@rollup/plugin-babel@5.3.1(@babel/core@7.22.1)(rollup@2.79.1):
resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==}
engines: {node: '>= 10.0.0'}
@ -1662,6 +1675,13 @@ packages:
resolution: {integrity: sha512-IthPJsJR85GhOkp3Hvp8zFOPK5ynKn6STyHa/WZpioK7E1aYDiBzpqQPrngc14DszIUkIrdd3k9Iu0XSzlP/1w==}
dev: true
/@selderee/plugin-htmlparser2@0.10.0:
resolution: {integrity: sha512-gW69MEamZ4wk1OsOq1nG1jcyhXIQcnrsX5JwixVw/9xaiav8TCyjESAruu1Rz9yyInhgBXxkNwMeygKnN2uxNA==}
dependencies:
domhandler: 5.0.3
selderee: 0.10.0
dev: false
/@sindresorhus/is@4.6.0:
resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
engines: {node: '>=10'}
@ -2136,6 +2156,10 @@ packages:
resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==}
dev: true
/abbrev@1.1.1:
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
dev: false
/ably@1.2.40:
resolution: {integrity: sha512-Rmc/IBW9BQeDqaVZdeYD2HMakfzoumHw8Ag3JtqxdC8xcc50k69FDY3Y1t9Mp7nrDQDjDYXvHgiOkVp99jNjHA==}
engines: {node: '>=5.10.x'}
@ -2317,6 +2341,10 @@ packages:
resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==}
dev: true
/asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
dev: false
/at-least-node@1.0.0:
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
engines: {node: '>= 4.0.0'}
@ -2348,6 +2376,16 @@ packages:
engines: {node: '>=4'}
dev: true
/axios@1.4.0:
resolution: {integrity: sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==}
dependencies:
follow-redirects: 1.15.2
form-data: 4.0.0
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
dev: false
/axobject-query@3.1.1:
resolution: {integrity: sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==}
dependencies:
@ -2407,7 +2445,6 @@ packages:
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
/base64-js@1.0.2:
resolution: {integrity: sha512-ZXBDPMt/v/8fsIqn+Z5VwrhdR6jVka0bYobHdGia0Nxi7BJ9i/Uvml3AocHIBtIIBhZjBw5MR0aR4ROs/8+SNg==}
@ -2465,7 +2502,6 @@ packages:
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
dependencies:
balanced-match: 1.0.2
dev: true
/braces@3.0.2:
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
@ -2651,9 +2687,15 @@ packages:
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
dev: true
/combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
dependencies:
delayed-stream: 1.0.0
dev: false
/commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
dev: true
/commander@4.1.1:
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
@ -2678,6 +2720,22 @@ packages:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: true
/condense-newlines@0.2.1:
resolution: {integrity: sha512-P7X+QL9Hb9B/c8HI5BFFKmjgBu2XpQuF98WZ9XkO+dBGgk5XgwiQz7o1SmpglNWId3581UcS0SFAWfoIhMHPfg==}
engines: {node: '>=0.10.0'}
dependencies:
extend-shallow: 2.0.1
is-whitespace: 0.3.0
kind-of: 3.2.2
dev: false
/config-chain@1.1.13:
resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
dependencies:
ini: 1.3.8
proto-list: 1.2.4
dev: false
/convert-source-map@1.9.0:
resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
@ -2812,7 +2870,6 @@ packages:
/deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
dev: true
/default-browser-id@3.0.0:
resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==}
@ -2863,6 +2920,11 @@ packages:
rimraf: 2.7.1
dev: true
/delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
dev: false
/denque@2.1.0:
resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
engines: {node: '>=0.10'}
@ -2902,6 +2964,43 @@ packages:
esutils: 2.0.3
dev: true
/dom-serializer@2.0.0:
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
dependencies:
domelementtype: 2.3.0
domhandler: 5.0.3
entities: 4.5.0
dev: false
/domelementtype@2.3.0:
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
dev: false
/domhandler@5.0.3:
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
engines: {node: '>= 4'}
dependencies:
domelementtype: 2.3.0
dev: false
/domutils@3.1.0:
resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==}
dependencies:
dom-serializer: 2.0.0
domelementtype: 2.3.0
domhandler: 5.0.3
dev: false
/editorconfig@0.15.3:
resolution: {integrity: sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==}
hasBin: true
dependencies:
commander: 2.20.3
lru-cache: 4.1.5
semver: 5.7.1
sigmund: 1.0.1
dev: false
/ejs@3.1.9:
resolution: {integrity: sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==}
engines: {node: '>=0.10.0'}
@ -2936,6 +3035,11 @@ packages:
tapable: 2.2.1
dev: true
/entities@4.5.0:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
dev: false
/es-abstract@1.21.2:
resolution: {integrity: sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==}
engines: {node: '>= 0.4'}
@ -3362,6 +3466,13 @@ packages:
engines: {node: '>=6'}
dev: false
/extend-shallow@2.0.1:
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
engines: {node: '>=0.10.0'}
dependencies:
is-extendable: 0.1.1
dev: false
/fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: true
@ -3456,12 +3567,31 @@ packages:
resolution: {integrity: sha512-OLmulPKywj1ETsAGeNTaxOmrFdffLFr97Gc/Bfmwu80mS1ToyvTDGNcMa16rCScBabd7M+UlCDSgpafjrTyCJw==}
dev: false
/follow-redirects@1.15.2:
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
dev: false
/for-each@0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
dependencies:
is-callable: 1.2.7
dev: true
/form-data@4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
engines: {node: '>= 6'}
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.35
dev: false
/fraction.js@4.2.0:
resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
dev: false
@ -3482,7 +3612,6 @@ packages:
/fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
dev: true
/fsevents@2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
@ -3608,6 +3737,17 @@ packages:
path-is-absolute: 1.0.1
dev: true
/glob@8.1.0:
resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
engines: {node: '>=12'}
dependencies:
fs.realpath: 1.0.0
inflight: 1.0.6
inherits: 2.0.4
minimatch: 5.1.6
once: 1.4.0
dev: false
/globals@11.12.0:
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
engines: {node: '>=4'}
@ -3738,6 +3878,26 @@ packages:
function-bind: 1.1.1
dev: true
/html-to-text@9.0.3:
resolution: {integrity: sha512-hxDF1kVCF2uw4VUJ3vr2doc91pXf2D5ngKcNviSitNkhP9OMOaJkDrFIFL6RMvko7NisWTEiqGpQ9LAxcVok1w==}
engines: {node: '>=14'}
dependencies:
'@selderee/plugin-htmlparser2': 0.10.0
deepmerge: 4.3.1
dom-serializer: 2.0.0
htmlparser2: 8.0.2
selderee: 0.10.0
dev: false
/htmlparser2@8.0.2:
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
dependencies:
domelementtype: 2.3.0
domhandler: 5.0.3
domutils: 3.1.0
entities: 4.5.0
dev: false
/http-cache-semantics@4.1.1:
resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
dev: false
@ -3791,7 +3951,6 @@ packages:
dependencies:
once: 1.4.0
wrappy: 1.0.2
dev: true
/inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@ -3867,6 +4026,10 @@ packages:
has-tostringtag: 1.0.0
dev: true
/is-buffer@1.1.6:
resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
dev: false
/is-callable@1.2.7:
resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
engines: {node: '>= 0.4'}
@ -3897,6 +4060,11 @@ packages:
hasBin: true
dev: true
/is-extendable@0.1.1:
resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
engines: {node: '>=0.10.0'}
dev: false
/is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
@ -4051,6 +4219,11 @@ packages:
engines: {node: '>=12.13'}
dev: false
/is-whitespace@0.3.0:
resolution: {integrity: sha512-RydPhl4S6JwAyj0JJjshWJEFG6hNye3pZFBRZaTUfZFwGHxzppNaNOVgQuS/E/SlhrApuMXrpnK1EEIXfdo3Dg==}
engines: {node: '>=0.10.0'}
dev: false
/is-wsl@2.2.0:
resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
engines: {node: '>=8'}
@ -4104,6 +4277,17 @@ packages:
resolution: {integrity: sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==}
dev: false
/js-beautify@1.14.8:
resolution: {integrity: sha512-4S7HFeI9YfRvRgKnEweohs0tgJj28InHVIj4Nl8Htf96Y6pHg3+tJrmo4ucAM9f7l4SHbFI3IvFAZ2a1eQPbyg==}
engines: {node: '>=12'}
hasBin: true
dependencies:
config-chain: 1.1.13
editorconfig: 0.15.3
glob: 8.1.0
nopt: 6.0.0
dev: false
/js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@ -4197,6 +4381,13 @@ packages:
json-buffer: 3.0.1
dev: false
/kind-of@3.2.2:
resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==}
engines: {node: '>=0.10.0'}
dependencies:
is-buffer: 1.1.6
dev: false
/language-subtag-registry@0.3.22:
resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==}
dev: true
@ -4207,6 +4398,10 @@ packages:
language-subtag-registry: 0.3.22
dev: true
/leac@0.6.0:
resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==}
dev: false
/leven@3.1.0:
resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
engines: {node: '>=6'}
@ -4296,6 +4491,13 @@ packages:
engines: {node: '>=8'}
dev: false
/lru-cache@4.1.5:
resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
dependencies:
pseudomap: 1.0.2
yallist: 2.1.2
dev: false
/lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
dependencies:
@ -4340,14 +4542,12 @@ packages:
/mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
dev: true
/mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
dependencies:
mime-db: 1.52.0
dev: true
/mimic-fn@2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
@ -4380,7 +4580,6 @@ packages:
engines: {node: '>=10'}
dependencies:
brace-expansion: 2.0.1
dev: true
/minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
@ -4527,6 +4726,14 @@ packages:
/node-releases@2.0.12:
resolution: {integrity: sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==}
/nopt@6.0.0:
resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
hasBin: true
dependencies:
abbrev: 1.1.1
dev: false
/normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
@ -4741,6 +4948,13 @@ packages:
callsites: 3.1.0
dev: true
/parseley@0.11.0:
resolution: {integrity: sha512-VfcwXlBWgTF+unPcr7yu3HSSA6QUdDaDnrHcytVfj5Z8azAyKBDrYnSIfeSxlrEayndNcLmrXzg+Vxbo6DWRXQ==}
dependencies:
leac: 0.6.0
peberminta: 0.8.0
dev: false
/path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
@ -4774,6 +4988,10 @@ packages:
engines: {node: '>=8'}
dev: true
/peberminta@0.8.0:
resolution: {integrity: sha512-YYEs+eauIjDH5nUEGi18EohWE0nV2QbGTqmxQcqgZ/0g+laPCQmuIqq7EBLVi9uim9zMgfJv0QBZEnQ3uHw/Tw==}
dev: false
/picocolors@1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
@ -4938,6 +5156,15 @@ packages:
resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==}
dev: false
/pretty@2.0.0:
resolution: {integrity: sha512-G9xUchgTEiNpormdYBl+Pha50gOUovT18IvAe7EYMZ1/f9W/WWMPRn+xI68yXNMUk3QXHDwo/1wV/4NejVNe1w==}
engines: {node: '>=0.10.0'}
dependencies:
condense-newlines: 0.2.1
extend-shallow: 2.0.1
js-beautify: 1.14.8
dev: false
/prisma@4.15.0:
resolution: {integrity: sha512-iKZZpobPl48gTcSZVawLMQ3lEy6BnXwtoMj7hluoGFYu2kQ6F9LBuBrUyF95zRVnNo8/3KzLXJXJ5TEnLSJFiA==}
engines: {node: '>=14.17'}
@ -4954,6 +5181,18 @@ packages:
react-is: 16.13.1
dev: true
/proto-list@1.2.4:
resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
dev: false
/proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
dev: false
/pseudomap@1.0.2:
resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
dev: false
/pump@3.0.0:
resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
dependencies:
@ -5121,6 +5360,15 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/resend@0.15.1:
resolution: {integrity: sha512-FcI1JTCM4OuFhXT5gKO6krcq7Cb7gAnP+cyKZqDt4nfBk3NPaFuzCqunMlyYt8CAJ+hCg2P98owaxFtZwUJLIg==}
dependencies:
'@react-email/render': 0.0.7
axios: 1.4.0
transitivePeerDependencies:
- debug
dev: false
/resolve-alpn@1.2.1:
resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
dev: false
@ -5245,6 +5493,17 @@ packages:
ajv-keywords: 3.5.2(ajv@6.12.6)
dev: true
/selderee@0.10.0:
resolution: {integrity: sha512-DEL/RW/f4qLw/NrVg97xKaEBC8IpzIG2fvxnzCp3Z4yk4jQ3MXom+Imav9wApjxX2dfS3eW7x0DXafJr85i39A==}
dependencies:
parseley: 0.11.0
dev: false
/semver@5.7.1:
resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
hasBin: true
dev: false
/semver@6.3.0:
resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
hasBin: true
@ -5303,6 +5562,10 @@ packages:
object-inspect: 1.12.3
dev: true
/sigmund@1.0.1:
resolution: {integrity: sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==}
dev: false
/signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
dev: true
@ -6142,6 +6405,10 @@ packages:
async-limiter: 1.0.1
dev: false
/yallist@2.1.2:
resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
dev: false
/yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}

View file

@ -0,0 +1,18 @@
import * as React from "react";
interface EmailTemplateProps {
name: string;
}
export const Goodbye: React.FC<Readonly<EmailTemplateProps>> = ({ name }) => (
<div>
<h1>Welcome, {name}!</h1>
<p>We're sorry to see you go!</p>
<p>
Your data has been deleted, including all room history, user data, votes,
etc.
</p>
<br />
<p>Sprint Padawan Admin - Atridad</p>
</div>
);

View file

@ -0,0 +1,18 @@
import * as React from "react";
interface EmailTemplateProps {
name: string;
}
export const Welcome: React.FC<Readonly<EmailTemplateProps>> = ({ name }) => (
<div>
<h1>Welcome, {name}!</h1>
<p>Thank you for signing up for Sprint Padawan!</p>
<p>
If at any point you encounter issues, please let me know at
support@sprintpadawan.dev.
</p>
<br />
<p>Sprint Padawan Admin - Atridad</p>
</div>
);

View file

@ -44,9 +44,7 @@ const server = z.object({
GOOGLE_CLIENT_SECRET: z.string(),
ABLY_PRIVATE_KEY: z.string(),
APP_ENV: z.string(),
JMAP_TOKEN: z.string(),
JMAP_USERNAME: z.string(),
JMAP_HOSTNAME: z.string(),
RESEND_API_KEY: z.string(),
});
/**
@ -78,9 +76,7 @@ const processEnv = {
NEXT_PUBLIC_ABLY_PUBLIC_KEY: process.env.NEXT_PUBLIC_ABLY_PUBLIC_KEY,
APP_ENV: process.env.APP_ENV,
NEXT_PUBLIC_APP_ENV: process.env.NEXT_PUBLIC_APP_ENV,
JMAP_TOKEN: process.env.JMAP_TOKEN,
JMAP_USERNAME: process.env.JMAP_USERNAME,
JMAP_HOSTNAME: process.env.JMAP_HOSTNAME,
RESEND_API_KEY: process.env.RESEND_API_KEY,
};
// Don't touch the part below

View file

@ -7,6 +7,7 @@ import { api } from "~/utils/api";
import { IoTrashBinOutline } from "react-icons/io5";
import { AiOutlineClear } from "react-icons/ai";
import { FaShieldAlt } from "react-icons/fa";
import { SiGoogle, SiGithub } from "react-icons/si";
import type { Role } from "~/utils/types";
export const getServerSideProps: GetServerSideProps = async (ctx) => {
@ -81,6 +82,24 @@ const AdminBody: React.FC = () => {
refetch: refetchVotesCount,
} = api.vote.countAll.useQuery();
const getProviders = (user: {
createdAt: Date;
accounts: {
provider: string;
}[];
sessions: {
id: string;
}[];
id: string;
role: Role;
name: string | null;
email: string | null;
}) => {
return user.accounts.map((account) => {
return account.provider;
});
};
const deleteUserMutation = api.user.delete.useMutation({
onSuccess: async () => {
await refetchData();
@ -186,6 +205,7 @@ const AdminBody: React.FC = () => {
<th>Name</th>
<th>Created At</th>
<th># Sessions</th>
<th>Providers</th>
<th>Actions</th>
</tr>
</thead>
@ -210,6 +230,14 @@ const AdminBody: React.FC = () => {
<td className="max-w-[100px] break-normal">
{user.sessions.length}
</td>
<td className="max-w-[100px] break-normal">
{getProviders(user).includes("google") && (
<SiGoogle className="text-xl m-1 inline-block hover:text-secondary" />
)}
{getProviders(user).includes("github") && (
<SiGithub className="text-xl m-1 inline-block hover:text-secondary" />
)}
</td>
<td>
<button className="m-2">
{user.role === "ADMIN" ? (

View file

@ -2,8 +2,9 @@ import type { User } from "@prisma/client";
import { z } from "zod";
import { env } from "~/env.mjs";
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
import { sendMail } from "fms-ts";
import type { Role } from "~/utils/types";
import { Resend } from "resend";
import { Goodbye } from "~/components/templates/Goodbye";
import {
cacheClient,
@ -13,6 +14,7 @@ import {
} from "redicache-ts";
const client = cacheClient(env.REDIS_URL);
const resend = new Resend(process.env.RESEND_API_KEY);
export const userRouter = createTRPCRouter({
countAll: protectedProcedure.query(async ({ ctx }) => {
@ -38,6 +40,7 @@ export const userRouter = createTRPCRouter({
return usersCount;
}
}),
getProviders: protectedProcedure.query(async ({ ctx }) => {
const providers = await ctx.prisma.user.findUnique({
where: {
@ -59,6 +62,9 @@ export const userRouter = createTRPCRouter({
getAll: protectedProcedure.query(async ({ ctx }) => {
const cachedResult = await fetchFromCache<
{
accounts: {
provider: string;
}[];
sessions: {
id: string;
}[];
@ -90,6 +96,11 @@ export const userRouter = createTRPCRouter({
id: true,
},
},
accounts: {
select: {
provider: true,
},
},
},
});
@ -129,22 +140,13 @@ export const userRouter = createTRPCRouter({
}
if (!!user && user.name && user.email) {
const subject = "Sorry to see you go... 😭";
const body =
`Hi ${user.name}! \n\n` +
"We're sorry to see you go! \n" +
"Your data has been deleted, including all room history, user data, votes, etc. \n" +
"-- \n" +
"Sprint Padawan Admin - Atridad \n";
await sendMail(
env.JMAP_USERNAME,
env.JMAP_TOKEN,
subject,
body,
user.email
);
await resend.sendEmail({
from: "no-reply@sprintpadawan.dev",
to: user.email,
subject: "Sorry to see you go... 😭",
//@ts-ignore
react: Goodbye({ name: user.name }),
});
await deleteFromCache(client, env.APP_ENV, `kv_usercount_admin`);
await deleteFromCache(client, env.APP_ENV, `kv_userlist_admin`);
}

View file

@ -10,10 +10,12 @@ import { PrismaAdapter } from "@next-auth/prisma-adapter";
import { env } from "~/env.mjs";
import { prisma } from "~/server/db";
import type { Role } from "~/utils/types";
import { sendMail } from "fms-ts";
import { Resend } from "resend";
import { Welcome } from "../components/templates/Welcome";
import { cacheClient, deleteFromCache } from "redicache-ts";
const client = cacheClient(env.REDIS_URL);
const resend = new Resend(process.env.RESEND_API_KEY);
/**
* Module augmentation for `next-auth` types. Allows us to add custom properties to the `session`
@ -52,22 +54,13 @@ export const authOptions: NextAuthOptions = {
events: {
async createUser({ user }) {
if (user && user.name && user.email) {
const subject = "🎉 Welcome to Sprint Padawan! 🎉";
const body =
`Hi ${user.name}! \n\n` +
"Thank you for signing up for Sprint Padawan! \n" +
"If at any point you encounter issues, please let me know at support@sprintpadawan.dev. \n" +
"-- \n" +
"Sprint Padawan Admin - Atridad \n";
await sendMail(
env.JMAP_USERNAME,
env.JMAP_TOKEN,
subject,
body,
user.email
);
await resend.sendEmail({
from: "no-reply@sprintpadawan.dev",
to: user.email,
subject: "🎉 Welcome to Sprint Padawan! 🎉",
//@ts-ignore
react: Welcome({ name: user.name }),
});
await deleteFromCache(client, env.APP_ENV, `kv_userlist_admin`);
await deleteFromCache(client, env.APP_ENV, `kv_usercount_admin`);
}