Merge pull request #390 from Irev-Dev/main
release 29th June 2021
This commit was merged in pull request #390.
This commit is contained in:
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"Hutten"
|
||||
"Hutten",
|
||||
"sendmail"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -17,3 +17,14 @@ CLOUDINARY_API_KEY=476712943135152
|
||||
# See: https://redwoodjs.com/docs/logger for level options:
|
||||
# trace | info | debug | warn | error | silent
|
||||
# LOG_LEVEL=debug
|
||||
|
||||
|
||||
# EMAIL_PASSWORD=abc123
|
||||
|
||||
|
||||
CAD_LAMBDA_BASE_URL="http://localhost:8080"
|
||||
|
||||
# sentry
|
||||
GITHUB_ASSIST_APP_ID=23342
|
||||
GITHUB_ASSIST_SECRET=abc
|
||||
GITHUB_ASSIST_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nabcdefg\n-----END RSA PRIVATE KEY-----"
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
"dependencies": {
|
||||
"@redwoodjs/api": "^0.34.1",
|
||||
"@sentry/node": "^6.5.1",
|
||||
"cloudinary": "^1.23.0"
|
||||
"cloudinary": "^1.23.0",
|
||||
"nodemailer": "^6.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/nodemailer": "^6.4.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ Because of the way the docker containers to be deployed as lambdas on aws are so
|
||||
|
||||
The docker build relies on a git ignored file, the aws-lambda-rie. [Download it](https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/download/v1.0/aws-lambda-rie), then put it into `app/api/src/docker/common/`. alternatively you can put this download into the DockerFiles by reading the instructions at around line 29 of the DockerFiles (`app/api/src/docker/openscad/Dockerfile` & `app/api/src/docker/cadquery/Dockerfile`). However this will mean slower build times as it will need download this 14mb file every build.
|
||||
|
||||
you will also need to create a .env in `app/api/src/docker/.env` for the following env-vars `DEV_AWS_SECRET_ACCESS_KEY, DEV_AWS_ACCESS_KEY_ID and DEV_BUCKET`. Ask @irev-dev for credentials and he can sort you out.
|
||||
|
||||
Then cd into this folder `cd api/src/docker` and:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -10,19 +10,22 @@ app.use(cors())
|
||||
const invocationURL = (port) =>
|
||||
`http://localhost:${port}/2015-03-31/functions/function/invocations`
|
||||
|
||||
const makeRequest = (route, port) => [route, async (req, res) => {
|
||||
console.log(`making post request to ${port}, ${route}`)
|
||||
try {
|
||||
const { data } = await axios.post(invocationURL(port), {
|
||||
body: JSON.stringify(req.body),
|
||||
})
|
||||
res.status(data.statusCode)
|
||||
res.send(data.body)
|
||||
} catch (e) {
|
||||
res.status(500)
|
||||
res.send()
|
||||
}
|
||||
}]
|
||||
const makeRequest = (route, port) => [
|
||||
route,
|
||||
async (req, res) => {
|
||||
console.log(`making post request to ${port}, ${route}`)
|
||||
try {
|
||||
const { data } = await axios.post(invocationURL(port), {
|
||||
body: JSON.stringify(req.body),
|
||||
})
|
||||
res.status(data.statusCode)
|
||||
res.send(data.body)
|
||||
} catch (e) {
|
||||
res.status(500)
|
||||
res.send()
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
app.post(...makeRequest('/openscad/preview', 5052))
|
||||
app.post(...makeRequest('/openscad/stl', 5053))
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
const { makeFile, runCommand } = require('../common/utils')
|
||||
const { nanoid } = require('nanoid')
|
||||
|
||||
module.exports.runCQ = async ({ file, settings: {
|
||||
deflection = 0.3
|
||||
} = {} } = {}) => {
|
||||
module.exports.runCQ = async ({
|
||||
file,
|
||||
settings: { deflection = 0.3 } = {},
|
||||
} = {}) => {
|
||||
const tempFile = await makeFile(file, '.py', nanoid)
|
||||
const fullPath = `/tmp/${tempFile}/output.stl`
|
||||
const command = `cq-cli/cq-cli --codec stl --infile /tmp/${tempFile}/main.py --outfile ${fullPath} --outputopts "deflection:${deflection};angularDeflection:${deflection};"`
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
services:
|
||||
# aws-emulator:
|
||||
# build: .
|
||||
# networks:
|
||||
# - awsland
|
||||
# ports:
|
||||
# - "5050:8080"
|
||||
|
||||
openscad-health:
|
||||
build:
|
||||
context: ./
|
||||
dockerfile: ./openscad/.
|
||||
dockerfile: ./openscad/Dockerfile
|
||||
image: openscad
|
||||
command: openscad.health
|
||||
ports:
|
||||
@@ -17,10 +11,7 @@ services:
|
||||
|
||||
openscad-preview:
|
||||
image: openscad
|
||||
# build: ./openscad/.
|
||||
command: openscad.preview
|
||||
# networks:
|
||||
# - awsland
|
||||
ports:
|
||||
- "5052:8080"
|
||||
environment:
|
||||
@@ -30,7 +21,6 @@ services:
|
||||
|
||||
openscad-stl:
|
||||
image: openscad
|
||||
# build: ./openscad/.
|
||||
command: openscad.stl
|
||||
ports:
|
||||
- "5053:8080"
|
||||
@@ -42,7 +32,7 @@ services:
|
||||
cadquery-stl:
|
||||
build:
|
||||
context: ./
|
||||
dockerfile: ./cadquery/.
|
||||
dockerfile: ./cadquery/Dockerfile
|
||||
command: cadquery.stl
|
||||
ports:
|
||||
- 5060:8080
|
||||
@@ -51,6 +41,3 @@ services:
|
||||
AWS_ACCESS_KEY_ID: "${DEV_AWS_ACCESS_KEY_ID}"
|
||||
BUCKET: "${DEV_BUCKET}"
|
||||
|
||||
# networks:
|
||||
# awsland:
|
||||
# name: awsland
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { createUserInsecure } from 'src/services/users/users.js'
|
||||
import { createUserInsecure } from 'src/services/users/users'
|
||||
import { db } from 'src/lib/db'
|
||||
import { sentryWrapper } from 'src/lib/sentry'
|
||||
import { enforceAlphaNumeric, generateUniqueString } from 'src/services/helpers'
|
||||
import 'graphql-tag'
|
||||
import { sendMail } from 'src/lib/sendmail'
|
||||
|
||||
const unWrappedHandler = async (req, _context) => {
|
||||
const body = JSON.parse(req.body)
|
||||
@@ -56,7 +57,7 @@ const unWrappedHandler = async (req, _context) => {
|
||||
const user = body.user
|
||||
const email = user.email
|
||||
|
||||
let roles = []
|
||||
const roles = []
|
||||
|
||||
if (eventType === 'signup') {
|
||||
roles.push('user')
|
||||
@@ -73,6 +74,15 @@ const unWrappedHandler = async (req, _context) => {
|
||||
id: user.id,
|
||||
}
|
||||
await createUserInsecure({ input })
|
||||
await sendMail({
|
||||
to: 'k.hutten@protonmail.ch',
|
||||
from: {
|
||||
address: 'news@mail.cadhub.xyz',
|
||||
name: 'CadHub',
|
||||
},
|
||||
subject: `New Cadhub User`,
|
||||
text: JSON.stringify(input, null, 2),
|
||||
})
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
22
app/api/src/graphql/email.sdl.ts
Normal file
22
app/api/src/graphql/email.sdl.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
export const schema = gql`
|
||||
type Envelope {
|
||||
from: String
|
||||
to: [String!]!
|
||||
}
|
||||
|
||||
type EmailResponse {
|
||||
accepted: [String!]!
|
||||
rejected: [String!]!
|
||||
messageId: String!
|
||||
envelope: Envelope
|
||||
}
|
||||
|
||||
input Email {
|
||||
subject: String!
|
||||
body: String!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
sendAllUsersEmail(input: Email!): EmailResponse!
|
||||
}
|
||||
`
|
||||
@@ -121,7 +121,8 @@ export const getCurrentUser = async (decoded, { _token, _type }) => {
|
||||
* requireAuth({ role: ['editor', 'author'] })
|
||||
* requireAuth({ role: ['publisher'] })
|
||||
*/
|
||||
export const requireAuth = ({ role } = {}) => {
|
||||
export const requireAuth = ({ role }: { role?: string | string[] } = {}) => {
|
||||
console.log(context.currentUser)
|
||||
if (!context.currentUser) {
|
||||
throw new AuthenticationError("You don't have permission to do that.")
|
||||
}
|
||||
63
app/api/src/lib/sendmail.ts
Normal file
63
app/api/src/lib/sendmail.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import nodemailer, { SendMailOptions } from 'nodemailer'
|
||||
|
||||
interface Args {
|
||||
to: SendMailOptions['to']
|
||||
from: SendMailOptions['from']
|
||||
subject: string
|
||||
text: string
|
||||
}
|
||||
|
||||
interface SuccessResult {
|
||||
accepted: string[]
|
||||
rejected: string[]
|
||||
envelopeTime: number
|
||||
messageTime: number
|
||||
messageSize: number
|
||||
response: string
|
||||
envelope: {
|
||||
from: string | false
|
||||
to: string[]
|
||||
}
|
||||
messageId: string
|
||||
}
|
||||
|
||||
export function sendMail({
|
||||
to,
|
||||
from,
|
||||
subject,
|
||||
text,
|
||||
}: Args): Promise<SuccessResult> {
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: 'smtp.mailgun.org',
|
||||
port: 587,
|
||||
secure: false,
|
||||
tls: {
|
||||
ciphers: 'SSLv3',
|
||||
},
|
||||
auth: {
|
||||
user: 'postmaster@mail.cadhub.xyz',
|
||||
pass: process.env.EMAIL_PASSWORD,
|
||||
},
|
||||
})
|
||||
|
||||
console.log({ to, from, subject, text })
|
||||
|
||||
const emailPromise = new Promise((resolve, reject) => {
|
||||
transporter.sendMail(
|
||||
{
|
||||
from,
|
||||
to,
|
||||
subject,
|
||||
text,
|
||||
},
|
||||
(error, info) => {
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve(info)
|
||||
}
|
||||
}
|
||||
)
|
||||
}) as any as Promise<SuccessResult>
|
||||
return emailPromise
|
||||
}
|
||||
26
app/api/src/services/email/email.ts
Normal file
26
app/api/src/services/email/email.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { requireAuth } from 'src/lib/auth'
|
||||
import { sendMail } from 'src/lib/sendmail'
|
||||
import { users } from 'src/services/users/users'
|
||||
|
||||
export const sendAllUsersEmail = async ({ input: { body, subject } }) => {
|
||||
requireAuth({ role: 'admin' })
|
||||
const recipients = (await users()).map(({ email }) => email)
|
||||
const from = {
|
||||
address: 'news@mail.cadhub.xyz',
|
||||
name: 'CadHub',
|
||||
}
|
||||
const result = await sendMail({
|
||||
to: recipients,
|
||||
from,
|
||||
subject,
|
||||
text: body,
|
||||
})
|
||||
await sendMail({
|
||||
to: 'k.hutten@protonmail.ch',
|
||||
from,
|
||||
subject: `All users email report`,
|
||||
text: JSON.stringify(result, null, 2),
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -16,7 +16,8 @@
|
||||
'SENTRY_DSN',
|
||||
'SENTRY_AUTH_TOKEN',
|
||||
'SENTRY_ORG',
|
||||
'SENTRY_PROJECT'
|
||||
'SENTRY_PROJECT',
|
||||
'EMAIL_PASSWORD'
|
||||
]
|
||||
# experimentalFastRefresh = true # this seems to break cascadeStudio
|
||||
[api]
|
||||
|
||||
@@ -62,6 +62,7 @@ const Routes = () => {
|
||||
<Route path="/admin/subject-access-requests/{id}/edit" page={EditSubjectAccessRequestPage} name="editSubjectAccessRequest" />
|
||||
<Route path="/admin/subject-access-requests/{id}" page={SubjectAccessRequestPage} name="subjectAccessRequest" />
|
||||
<Route path="/admin/subject-access-requests" page={SubjectAccessRequestsPage} name="subjectAccessRequests" />
|
||||
<Route path="/admin/email" page={AdminEmailPage} name="adminEmail" />
|
||||
</Private>
|
||||
</Router>
|
||||
)
|
||||
|
||||
@@ -42,18 +42,15 @@ export const makeStlDownloadHandler =
|
||||
thunkDispatch((dispatch, getState) => {
|
||||
const state = getState()
|
||||
if (state.ideType === 'openScad') {
|
||||
thunkDispatch((dispatch, getState) => {
|
||||
const state = getState()
|
||||
dispatch({ type: 'setLoading' })
|
||||
requestRender({
|
||||
state,
|
||||
dispatch,
|
||||
code: state.code,
|
||||
viewerSize: state.viewerSize,
|
||||
camera: state.camera,
|
||||
specialCadProcess: 'stl',
|
||||
}).then((result) => result && saveFile(result.data))
|
||||
})
|
||||
dispatch({ type: 'setLoading' })
|
||||
requestRender({
|
||||
state,
|
||||
dispatch,
|
||||
code: state.code,
|
||||
viewerSize: state.viewerSize,
|
||||
camera: state.camera,
|
||||
specialCadProcess: 'stl',
|
||||
}).then((result) => result && saveFile(result.data))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -14,10 +14,7 @@ const Footer = () => {
|
||||
>
|
||||
Road Map
|
||||
</OutBound>
|
||||
<OutBound
|
||||
className="mr-8"
|
||||
to="https://learn.cadhub.xyz/blog"
|
||||
>
|
||||
<OutBound className="mr-8" to="https://learn.cadhub.xyz/blog">
|
||||
Blog
|
||||
</OutBound>
|
||||
<Link className="mr-8" to={routes.codeOfConduct()}>
|
||||
|
||||
@@ -13,7 +13,7 @@ import { requestRender } from 'src/helpers/hooks/useIdeState'
|
||||
import texture from './dullFrontLitMetal.png'
|
||||
import { TextureLoader } from 'three/src/loaders/TextureLoader'
|
||||
|
||||
const loader = new TextureLoader
|
||||
const loader = new TextureLoader()
|
||||
const colorMap = loader.load(texture)
|
||||
|
||||
extend({ OrbitControls })
|
||||
@@ -200,8 +200,8 @@ const IdeViewer = ({ Loading }) => {
|
||||
/>
|
||||
<ambientLight intensity={1} />
|
||||
<pointLight position={[15, 5, 10]} intensity={4} />
|
||||
<pointLight position={[-1000, -1000, -1000]} intensity={1}/>
|
||||
<pointLight position={[-1000, 0, 1000]} intensity={1}/>
|
||||
<pointLight position={[-1000, -1000, -1000]} intensity={1} />
|
||||
<pointLight position={[-1000, 0, 1000]} intensity={1} />
|
||||
{state.objectData?.type === 'png' && (
|
||||
<>
|
||||
<Sphere position={[0, 0, 0]} color={pink400} />
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
export const render = async ({ code }) => {
|
||||
const body = JSON.stringify({
|
||||
settings: {
|
||||
deflection: 0.2
|
||||
deflection: 0.2,
|
||||
},
|
||||
file: code,
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@ import { STLLoader } from 'three/examples/jsm/loaders/STLLoader'
|
||||
|
||||
export const lambdaBaseURL =
|
||||
process.env.CAD_LAMBDA_BASE_URL ||
|
||||
'https://2inlbple1b.execute-api.us-east-1.amazonaws.com/prod2'
|
||||
'https://oxt2p7ddgj.execute-api.us-east-1.amazonaws.com/prod'
|
||||
|
||||
export const stlToGeometry = (url) =>
|
||||
new Promise((resolve, reject) => {
|
||||
|
||||
59
app/web/src/pages/AdminEmailPage/AdminEmailPage.tsx
Normal file
59
app/web/src/pages/AdminEmailPage/AdminEmailPage.tsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import { useState } from 'react'
|
||||
import { useMutation } from '@redwoodjs/web'
|
||||
import { toast, Toaster } from '@redwoodjs/web/toast'
|
||||
|
||||
const SEND_EMAIL_MUTATION = gql`
|
||||
mutation sendEmailMutation($email: Email!) {
|
||||
sendAllUsersEmail(input: $email) {
|
||||
accepted
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const AdminEmailPage = () => {
|
||||
const [subject, setSubject] = useState('')
|
||||
const [body, setBody] = useState('')
|
||||
const [sendEmailMutation] = useMutation(SEND_EMAIL_MUTATION, {
|
||||
onCompleted: ({ sendAllUsersEmail }) => {
|
||||
toast.success(`Emails sent, ${sendAllUsersEmail?.accepted.join(', ')}`)
|
||||
setSubject('')
|
||||
setBody('')
|
||||
},
|
||||
})
|
||||
|
||||
const sendEmail = () =>
|
||||
sendEmailMutation({ variables: { email: { subject, body } } })
|
||||
|
||||
return (
|
||||
<div className="flex justify-center">
|
||||
<div className="max-w-7xl pt-8">
|
||||
<h2 className="" style={{ width: '46rem' }}>
|
||||
Email all users
|
||||
</h2>
|
||||
<label htmlFor="subject">Subject</label>
|
||||
<input
|
||||
name="subject"
|
||||
className="rounded border border-gray-400 px-2 w-full"
|
||||
value={subject}
|
||||
onChange={({ target }) => setSubject(target.value)}
|
||||
/>
|
||||
<label htmlFor="body">Body</label>
|
||||
<textarea
|
||||
className="w-full rounded border border-gray-400 p-2"
|
||||
name="text"
|
||||
value={body}
|
||||
onChange={({ target }) => setBody(target.value)}
|
||||
></textarea>
|
||||
<button
|
||||
className="rounded px-2 p-1 mt-4 bg-ch-purple-400 text-indigo-200"
|
||||
onClick={sendEmail}
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
</div>
|
||||
<Toaster timeout={1500} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AdminEmailPage
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import SubjectAccessRequestsCell from 'src/components/SubjectAccessRequestsCell'
|
||||
import { Flash, useQuery, useMutation, useFlash } from '@redwoodjs/web'
|
||||
import { useQuery, useMutation } from '@redwoodjs/web'
|
||||
import { Form, Submit } from '@redwoodjs/forms'
|
||||
|
||||
import MainLayout from 'src/layouts/MainLayout'
|
||||
|
||||
@@ -3963,6 +3963,13 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b"
|
||||
integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==
|
||||
|
||||
"@types/nodemailer@^6.4.2":
|
||||
version "6.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.2.tgz#d8ee254c969e6ad83fb9a0a0df3a817406a3fa3b"
|
||||
integrity sha512-yhsqg5Xbr8aWdwjFS3QjkniW5/tLpWXtOYQcJdo9qE3DolBxsKzgRCQrteaMY0hos8MklJNSEsMqDpZynGzMNg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/normalize-package-data@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
|
||||
@@ -13070,6 +13077,11 @@ node-releases@^1.1.29, node-releases@^1.1.61, node-releases@^1.1.71:
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.73.tgz#dd4e81ddd5277ff846b80b52bb40c49edf7a7b20"
|
||||
integrity sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==
|
||||
|
||||
nodemailer@^6.6.2:
|
||||
version "6.6.2"
|
||||
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.6.2.tgz#e184c9ed5bee245a3e0bcabc7255866385757114"
|
||||
integrity sha512-YSzu7TLbI+bsjCis/TZlAXBoM4y93HhlIgo0P5oiA2ua9Z4k+E2Fod//ybIzdJxOlXGRcHIh/WaeCBehvxZb/Q==
|
||||
|
||||
normalize-package-data@^2.3.2, normalize-package-data@^2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
|
||||
|
||||
Reference in New Issue
Block a user