release 29th June 2021 #390

Merged
Irev-Dev merged 6 commits from main into release 2021-06-29 10:57:26 +02:00
23 changed files with 257 additions and 59 deletions

View File

@@ -1,5 +1,6 @@
{
"cSpell.words": [
"Hutten"
"Hutten",
"sendmail"
]
}

View File

@@ -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-----"

View File

@@ -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"
}
}

View File

@@ -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

View File

@@ -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))

View File

@@ -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};"`

View File

@@ -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

View File

@@ -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,

View 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!
}
`

View File

@@ -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.")
}

View 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
}

View 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
}

View File

@@ -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]

View File

@@ -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>
)

View File

@@ -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))
}
})
}

View File

@@ -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()}>

View File

@@ -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} />

View File

@@ -9,7 +9,7 @@ import {
export const render = async ({ code }) => {
const body = JSON.stringify({
settings: {
deflection: 0.2
deflection: 0.2,
},
file: code,
})

View File

@@ -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) => {

View 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

View File

@@ -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'

View File

@@ -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"