3
src/env.d.ts
vendored
3
src/env.d.ts
vendored
@ -3,7 +3,10 @@
|
||||
interface ImportMetaEnv {
|
||||
CONFIGS_PATH?: string
|
||||
PRUSASLICER_PATH?: string
|
||||
BAMBUSTUDIO_PATH?: string
|
||||
MONGODB?: string
|
||||
PRIVATE_KEY?: string
|
||||
PUBLIC_KEY?: string
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
|
9
src/libs/AuthUtils.ts
Normal file
9
src/libs/AuthUtils.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import bcryptjs from 'bcryptjs'
|
||||
|
||||
export function hashPassword(password: string): Promise<string> {
|
||||
return bcryptjs.hash(password, 10)
|
||||
}
|
||||
|
||||
export function comparePassword(password: string, hash: string): Promise<boolean> {
|
||||
return bcryptjs.compare(password, hash)
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
import type { ServerResponse } from 'node:http'
|
||||
|
||||
export default class CookieManager {
|
||||
private cookies: Record<string, string> = {}
|
||||
public constructor(data?: string | Record<string, string>) {
|
||||
if (typeof data === 'string') {
|
||||
data.split(';').forEach((keyValuePair) => {
|
||||
const [key, value] = keyValuePair.split('=')
|
||||
if (!key || !value) {
|
||||
return
|
||||
}
|
||||
this.cookies[key.trim()] = value.trim().replace(/%3B/g, ';')
|
||||
})
|
||||
} else if (typeof data === 'object') {
|
||||
@ -13,7 +14,7 @@ export default class CookieManager {
|
||||
}
|
||||
}
|
||||
|
||||
public static addCookie(res: ServerResponse, cookie: {
|
||||
public static addCookie(res: ResponseInit & { readonly headers: Headers; }, cookie: {
|
||||
key: string
|
||||
value: string
|
||||
expire?: string
|
||||
@ -46,7 +47,7 @@ export default class CookieManager {
|
||||
if (cookie.sameSite) {
|
||||
items.push(`SameSite=${cookie.sameSite}`)
|
||||
}
|
||||
res.setHeader('Set-Cookie', items.join('; '))
|
||||
res.headers.append('Set-Cookie', items.join('; '))
|
||||
}
|
||||
|
||||
public get(key: string): string | undefined {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import DaoFactory from '../models/DaoFactory'
|
||||
import CookieManager from './CookieManager'
|
||||
import RFC7807, { buildRFC7807 } from './RFCs/RFC7807'
|
||||
import { buildRFC7807 } from './RFCs/RFC7807'
|
||||
|
||||
interface Permission {
|
||||
name: string
|
||||
|
@ -1,21 +1,83 @@
|
||||
import { objectOmit } from '@dzeio/object-util'
|
||||
import mongoose from 'mongoose'
|
||||
import type Config from '.'
|
||||
import Client from '../Client'
|
||||
import Dao from '../Dao'
|
||||
|
||||
export default class ConfigDao extends Dao<Config> {
|
||||
private idx = 0
|
||||
public async create(obj: Omit<Config, 'id'>): Promise<Config | null> {
|
||||
console.log('pouet', this.idx++)
|
||||
return null
|
||||
// throw new Error('Method not implemented.')
|
||||
|
||||
// @ts-expect-error typing fix
|
||||
private model = mongoose.models['Config'] as null ?? mongoose.model('Config', new mongoose.Schema({
|
||||
user: { type: String, required: true },
|
||||
type: { type: String, required: true},
|
||||
files: [{
|
||||
name: { type: String, unique: true, required: true},
|
||||
data: { type: Buffer, required: true }
|
||||
}]
|
||||
}, {
|
||||
timestamps: true
|
||||
}))
|
||||
|
||||
|
||||
public async create(obj: Omit<Config, 'id' | 'created' | 'updated'>): Promise<Config | null> {
|
||||
await Client.get()
|
||||
return this.fromSource(await this.model.create(obj))
|
||||
}
|
||||
|
||||
public async findAll(query?: Partial<Config> | undefined): Promise<Config[]> {
|
||||
throw new Error('Method not implemented.')
|
||||
await Client.get()
|
||||
try {
|
||||
if (query?.id) {
|
||||
const item = await this.model.findById(new mongoose.Types.ObjectId(query.id))
|
||||
if (!item) {
|
||||
return []
|
||||
}
|
||||
return [this.fromSource(item)]
|
||||
}
|
||||
const resp = await this.model.find(query ? this.toSource(query as Config) : {})
|
||||
return resp.map(this.fromSource)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return []
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public async update(obj: Config): Promise<Config | null> {
|
||||
throw new Error('Method not implemented.')
|
||||
await Client.get()
|
||||
|
||||
const query = await this.model.updateOne({
|
||||
_id: new mongoose.Types.ObjectId(obj.id)
|
||||
}, this.toSource(obj))
|
||||
if (query.matchedCount >= 1) {
|
||||
obj.updated = new Date()
|
||||
return obj
|
||||
}
|
||||
return null
|
||||
// return this.fromSource()
|
||||
}
|
||||
|
||||
public async delete(obj: Config): Promise<boolean> {
|
||||
throw new Error('Method not implemented.')
|
||||
await Client.get()
|
||||
const res = await this.model.deleteOne({
|
||||
_id: new mongoose.Types.ObjectId(obj.id)
|
||||
})
|
||||
return res.deletedCount > 0
|
||||
}
|
||||
|
||||
private toSource(obj: Config): Omit<Config, 'id'> {
|
||||
return objectOmit(obj, 'id', 'updated', 'created')
|
||||
}
|
||||
|
||||
private fromSource(doc: mongoose.Document<any, any, Config>): Config {
|
||||
return {
|
||||
id: doc._id.toString(),
|
||||
user: doc.get('user'),
|
||||
type: doc.get('type'),
|
||||
files: doc.get('files') ?? [],
|
||||
updated: doc.get('updatedAt'),
|
||||
created: doc.get('createdAt')
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,11 @@
|
||||
import type User from '../User'
|
||||
|
||||
export default interface Config {
|
||||
id: string
|
||||
user: string
|
||||
type: 'prusa'
|
||||
files: Array<{
|
||||
name: string
|
||||
data: Buffer
|
||||
}>
|
||||
created: Date
|
||||
updated: Date
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import APIKeyDao from './APIKey/APIKeyDao'
|
||||
import ConfigDao from './Config/ConfigDao'
|
||||
import Dao from './Dao'
|
||||
import SessionDao from './Session/SessionDao'
|
||||
import UserDao from './User/UserDao'
|
||||
|
||||
/**
|
||||
@ -18,6 +18,7 @@ interface DaoItem {
|
||||
config: ConfigDao
|
||||
user: UserDao
|
||||
apiKey: APIKeyDao
|
||||
session: SessionDao
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,11 +55,12 @@ export default class DaoFactory {
|
||||
* @param item the element to init
|
||||
* @returns a new initialized dao or undefined if no dao is linked
|
||||
*/
|
||||
private static initDao(item: keyof DaoItem): Dao<any> | undefined {
|
||||
private static initDao(item: keyof DaoItem): any | undefined {
|
||||
switch (item) {
|
||||
case 'config': return new ConfigDao()
|
||||
case 'user': return new UserDao()
|
||||
case 'apiKey': return new APIKeyDao()
|
||||
case 'session': return new SessionDao()
|
||||
default: return undefined
|
||||
}
|
||||
}
|
||||
|
53
src/models/Session/SessionDao.ts
Normal file
53
src/models/Session/SessionDao.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import jwt, { SignOptions } from 'jsonwebtoken'
|
||||
import type Session from '.'
|
||||
import CookieManager from '../../libs/CookieManager'
|
||||
|
||||
export interface SessionOptions {
|
||||
cookieName: string
|
||||
security: SignOptions
|
||||
key?: string
|
||||
privateKey?: string
|
||||
publicKey?: string
|
||||
}
|
||||
|
||||
|
||||
export default class SessionDao {
|
||||
|
||||
private options: SessionOptions = {
|
||||
cookieName: 'session',
|
||||
security: {
|
||||
algorithm: 'ES512'
|
||||
},
|
||||
privateKey: import.meta.env.PRIVATE_KEY ?? '',
|
||||
publicKey: import.meta.env.PUBLIC_KEY ?? ''
|
||||
}
|
||||
|
||||
public getSession(req: Request): Session | null {
|
||||
const cookie = new CookieManager(req.headers.get('Cookie') ?? '').get(this.options.cookieName)
|
||||
if (!cookie) {
|
||||
return null
|
||||
}
|
||||
try {
|
||||
return jwt.verify(cookie, (this.options.publicKey || this.options.key) as string) as Session
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
public setSession(session: Session, res: ResponseInit & { readonly headers: Headers; }) {
|
||||
const token = jwt.sign(session, (this.options.privateKey || this.options.key) as string, this.options.security)
|
||||
CookieManager.addCookie(res, {
|
||||
key: this.options.cookieName,
|
||||
value: token,
|
||||
httpOnly: true,
|
||||
path: '/',
|
||||
secure: true,
|
||||
sameSite: 'Strict',
|
||||
maxAge: 365000
|
||||
})
|
||||
}
|
||||
|
||||
public removeSession(res: ResponseInit & { readonly headers: Headers; }) {
|
||||
|
||||
}
|
||||
}
|
3
src/models/Session/index.ts
Normal file
3
src/models/Session/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export default interface Session {
|
||||
userId: string
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { objectOmit } from '@dzeio/object-util'
|
||||
import mongoose, { ObjectId } from 'mongoose'
|
||||
import User from '.'
|
||||
import mongoose from 'mongoose'
|
||||
import type User from '.'
|
||||
import Client from '../Client'
|
||||
import Dao from '../Dao'
|
||||
|
||||
@ -8,7 +8,8 @@ export default class UserDao extends Dao<User> {
|
||||
|
||||
// @ts-expect-error typing fix
|
||||
private model = mongoose.models['User'] as null ?? mongoose.model('User', new mongoose.Schema({
|
||||
email: { type: String, required: true }
|
||||
email: { type: String, required: true },
|
||||
password: { type: String, required: true }
|
||||
}, {
|
||||
timestamps: true
|
||||
}))
|
||||
@ -62,6 +63,7 @@ export default class UserDao extends Dao<User> {
|
||||
return {
|
||||
id: doc._id.toString(),
|
||||
email: doc.get('email'),
|
||||
password: doc.get('password'),
|
||||
updated: doc.get('updatedAt'),
|
||||
created: doc.get('createdAt')
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
export default interface User {
|
||||
id: string
|
||||
email: string
|
||||
password: string
|
||||
created: Date
|
||||
updated: Date
|
||||
}
|
||||
|
@ -3,16 +3,23 @@ import URLManager from '@dzeio/url-manager'
|
||||
import Layout from '../../layouts/Layout.astro'
|
||||
import DaoFactory from '../../models/DaoFactory'
|
||||
import { comparePassword } from '../../libs/AuthUtils'
|
||||
import Passthrough from '../../components/Passthrough.astro'
|
||||
|
||||
const logout = new URLManager(Astro.url).query('logout')
|
||||
const logout = typeof new URLManager(Astro.url).query('logout') === 'string'
|
||||
|
||||
if (typeof logout === 'string') {
|
||||
if (logout) {
|
||||
DaoFactory.get('session').removeSession(Astro.response)
|
||||
}
|
||||
|
||||
// DaoFactory.get('session').removeSession(Astro.response)
|
||||
|
||||
if (Astro.request.method === 'POST') {
|
||||
let connected = false
|
||||
const sessionDao = DaoFactory.get('session')
|
||||
if (sessionDao.getSession(Astro.request) && !logout) {
|
||||
connected = true
|
||||
}
|
||||
|
||||
if (!connected && Astro.request.method === 'POST') {
|
||||
const form = await Astro.request.formData()
|
||||
const email = form.get('email') as string
|
||||
const password = form.get('password') as string
|
||||
@ -21,27 +28,39 @@ if (Astro.request.method === 'POST') {
|
||||
email
|
||||
})
|
||||
|
||||
if (!account) {
|
||||
return
|
||||
if (account) {
|
||||
const valid = await comparePassword(password, account.password)
|
||||
if (valid) {
|
||||
DaoFactory.get('session').setSession({
|
||||
userId: account.id
|
||||
}, Astro.response)
|
||||
connected = true
|
||||
}
|
||||
}
|
||||
const valid = await comparePassword(password, account.password)
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
DaoFactory.get('session').setSession({
|
||||
userId: account.id
|
||||
}, Astro.response)
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
<Layout title="Welcome to Astro.">
|
||||
<main>
|
||||
<form>
|
||||
<form method="post">
|
||||
<input type="email" name="email" />
|
||||
<input type="password" name="password" />
|
||||
<button>Connect</button>
|
||||
<button></button>
|
||||
</form>
|
||||
</main>
|
||||
<Passthrough connected={connected} />
|
||||
</Layout>
|
||||
|
||||
<script>import { load } from '../../components/Passthrough.astro'
|
||||
|
||||
const {
|
||||
connected
|
||||
} = load<{connected: boolean}>()
|
||||
|
||||
if (connected) {
|
||||
window.location = '/'
|
||||
}
|
||||
|
||||
</script>
|
||||
|
@ -7,19 +7,31 @@ const user = await DaoFactory.get('user').get('648f81f857503c7d29465318')
|
||||
const list = await DaoFactory.get('apiKey').findAll({
|
||||
user: user!.id
|
||||
})
|
||||
const configs = await DaoFactory.get('config').findAll({
|
||||
user: user!.id
|
||||
})
|
||||
const userId = user?.id ?? 'unknown'
|
||||
|
||||
---
|
||||
|
||||
<Layout title="Welcome to Astro.">
|
||||
<main>
|
||||
<h1>{user?.id}</h1>
|
||||
<ul>
|
||||
<li>API Keys</li>
|
||||
{list.map((it) => (
|
||||
<li>
|
||||
<p>access key: {it.key}</p>
|
||||
<p>permissions: {it.permissions}</p>
|
||||
</li>
|
||||
))}
|
||||
<li>Configurations</li>
|
||||
{configs.map((it) => (
|
||||
<li>
|
||||
<p>{it.id}: {it.type}</p>
|
||||
<p>{it.files.map((it) => it.name)}</p>
|
||||
</li>
|
||||
))}
|
||||
|
||||
<button>Create a new API Key</button>
|
||||
</ul>
|
||||
|
@ -1,15 +1,17 @@
|
||||
import Logger from '@dzeio/logger'
|
||||
import { objectMap, objectOmit } from '@dzeio/object-util'
|
||||
import URLManager from '@dzeio/url-manager'
|
||||
import type { APIRoute } from 'astro'
|
||||
import { evaluate } from 'mathjs'
|
||||
import { exec as execSync } from 'node:child_process'
|
||||
import { exec as execSync, spawn } from 'node:child_process'
|
||||
import fs from 'node:fs/promises'
|
||||
import os from 'node:os'
|
||||
import path from 'node:path/posix'
|
||||
import path from 'node:path'
|
||||
import { promisify } from 'node:util'
|
||||
import FilesUtils from '../../../libs/FilesUtils'
|
||||
import { buildRFC7807 } from '../../../libs/RFCs/RFC7807'
|
||||
import { getParams } from '../../../libs/gcodeUtils'
|
||||
import { validateAuth } from '../../../libs/validateAuth'
|
||||
import DaoFactory from '../../../models/DaoFactory'
|
||||
|
||||
const exec = promisify(execSync)
|
||||
|
||||
@ -21,50 +23,101 @@ let tmpDir: string
|
||||
* price: algorithm from settings
|
||||
* adionnal settings from https://manual.slic3r.org/advanced/command-line
|
||||
*/
|
||||
export const post: APIRoute = async ({ request }) => {
|
||||
export const post: APIRoute = async ({ params, request }) => {
|
||||
const res = await validateAuth(request, {
|
||||
name: 'slicing.slice',
|
||||
api: true,
|
||||
cookie: true
|
||||
})
|
||||
if (res) {
|
||||
return res
|
||||
}
|
||||
if (!tmpDir) {
|
||||
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'paas-'))
|
||||
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'saas-'))
|
||||
}
|
||||
|
||||
const configId = params.configId ?? 'undefined'
|
||||
const config = await DaoFactory.get('config').get(configId)
|
||||
|
||||
if (!config) {
|
||||
return buildRFC7807({
|
||||
type: '/missing-config',
|
||||
status: 404,
|
||||
title: 'The configuration does not exists',
|
||||
details: `The configuration ${configId} does not exists`
|
||||
})
|
||||
}
|
||||
|
||||
const query = new URLManager(request.url).query()
|
||||
const file = (Math.random() * 1000000).toFixed(0)
|
||||
console.log('started processing new request', file)
|
||||
await fs.mkdir(`${tmpDir}/files`, { recursive: true })
|
||||
|
||||
const overrides = objectOmit(query, 'algo', 'config')
|
||||
const configName = query?.config ?? 'config'
|
||||
let config = `${import.meta.env.CONFIGS_PATH}/` + configName + '.ini'
|
||||
if (!await FilesUtils.exists(config)) {
|
||||
console.log('request finished in error :(', file)
|
||||
return buildRFC7807({
|
||||
type: '/missing-config-file',
|
||||
status: 404,
|
||||
title: 'Configuration file is missing',
|
||||
details: `the configuration file "${configName}" is not available on the remote server`
|
||||
})
|
||||
const processId = (Math.random() * 1000000).toFixed(0)
|
||||
const logger = new Logger(`process-${processId}`)
|
||||
const processFolder = `${tmpDir}/${processId}`
|
||||
const pouet = await fs.mkdir(processFolder, { recursive: true })
|
||||
|
||||
logger.log('poeut', pouet)
|
||||
|
||||
logger.log('started processing request')
|
||||
|
||||
logger.log('writing configs to dir')
|
||||
for (const file of config.files) {
|
||||
await fs.writeFile(`${processFolder}/${file.name}`, file.data)
|
||||
}
|
||||
const stlPath = `${tmpDir}/files/${file}.stl`
|
||||
const gcodePath = `${tmpDir}/files/${file}.gcode`
|
||||
|
||||
// write file
|
||||
|
||||
const overrides = objectOmit(query, 'algo')
|
||||
|
||||
const stlPath = `${processFolder}/input.stl`
|
||||
const gcodePath = `${processFolder}/output.gcode`
|
||||
|
||||
logger.log('writing STL to filesystem')
|
||||
// write input
|
||||
await fs.writeFile(stlPath, new Uint8Array(Buffer.from(await request.arrayBuffer())), {
|
||||
encoding: null
|
||||
})
|
||||
// console.log(fs.statSync(stlPath).size, req.body.length)
|
||||
|
||||
// additionnal parameters
|
||||
let additionnalParams = objectMap(overrides, (value, key) => `--${(key as string).replace(/_/g, '-')} ${value}`).join(' ')
|
||||
const slicer = import.meta.env.PRUSASLICER_PATH ?? 'prusa-slicer'
|
||||
if (slicer.includes('prusa')) {
|
||||
|
||||
|
||||
let slicerPath: string
|
||||
let slicerCommand: string
|
||||
|
||||
if (config.type === 'prusa' || true) {
|
||||
slicerPath = import.meta.env.PRUSASLICER_PATH ?? 'prusa-slicer'
|
||||
additionnalParams += ' --export-gcode'
|
||||
slicerCommand = `${path.normalize(stlPath)} --load ${path.normalize(`${processFolder}/config.ini`)} --output ${path.normalize(gcodePath)} ${additionnalParams}`
|
||||
}
|
||||
const cmd = `${slicer} ${stlPath} --load ${config} --output ${gcodePath} ${additionnalParams}`
|
||||
|
||||
try {
|
||||
await exec(cmd, {
|
||||
timeout: 60000
|
||||
logger.log('Running', slicerPath, slicerCommand)
|
||||
await new Promise<void>((res, rej) => {
|
||||
const slicer = spawn(slicerPath, slicerCommand.split(' '))
|
||||
slicer.stdout.on('data', (data) => {
|
||||
logger.log('[stdout]',data.toString('utf8'))
|
||||
})
|
||||
slicer.stderr.on('data', (data: Buffer) => {
|
||||
logger.log('[stderr]', data.toString('utf8'))
|
||||
})
|
||||
slicer.on('error', (err) => {
|
||||
logger.log('error', err)
|
||||
rej(err)
|
||||
})
|
||||
slicer.on('close', (code, signal) => {
|
||||
logger.log('code', code)
|
||||
logger.log('signal', signal)
|
||||
if (typeof code === 'number' && code > 0) {
|
||||
|
||||
rej(code)
|
||||
return
|
||||
}
|
||||
res()
|
||||
})
|
||||
})
|
||||
} catch (e: any) {
|
||||
console.log('request finished in error :(', file)
|
||||
logger.log('request finished in error :(', processId)
|
||||
const line = e.toString()
|
||||
console.error(e)
|
||||
logger.error(e)
|
||||
if (line.includes('Objects could not fit on the bed')) {
|
||||
await fs.rm(stlPath)
|
||||
return buildRFC7807({
|
||||
@ -78,7 +131,7 @@ export const post: APIRoute = async ({ request }) => {
|
||||
type: '/missing-config-file',
|
||||
status: 404,
|
||||
title: 'Configuration file is missing',
|
||||
details: `the configuration file "${configName}" is not available on the remote server`
|
||||
details: `the configuration file "${configId}" is not available on the remote server`
|
||||
})
|
||||
} else if (line.includes('Unknown option')) {
|
||||
await fs.rm(stlPath)
|
||||
@ -115,18 +168,18 @@ export const post: APIRoute = async ({ request }) => {
|
||||
status: 500,
|
||||
title: 'General I/O error',
|
||||
details: 'A server error make it impossible to slice the file, please contact an administrator with the json error',
|
||||
fileId: file,
|
||||
config: configName,
|
||||
fileId: processId,
|
||||
config: configId,
|
||||
// fileSize: req.body.length,
|
||||
overrides: overrides,
|
||||
serverMessage:
|
||||
e.toString().replace(cmd, '***SLICER***').replace(stlPath, configName ?? `***FILE***`).replace(`${path}/configs/`, '').replace('.ini', '')
|
||||
e.toString().replace(new RegExp(stlPath), `***FILE***`).replace(new RegExp(processFolder), '')
|
||||
})
|
||||
}
|
||||
const gcode = await fs.readFile(gcodePath, 'utf-8')
|
||||
await fs.rm(stlPath)
|
||||
await fs.rm(gcodePath)
|
||||
const params = getParams(gcode)
|
||||
await fs.rm(processFolder, { recursive: true, force: true })
|
||||
logger.log('Getting parameters')
|
||||
const gcodeParams = getParams(gcode)
|
||||
let price: string | undefined
|
||||
if (query?.algo) {
|
||||
let algo = decodeURI(query.algo as string)
|
||||
@ -139,7 +192,8 @@ export const post: APIRoute = async ({ request }) => {
|
||||
// }
|
||||
// })
|
||||
try {
|
||||
const tmp = evaluate(algo, params)
|
||||
logger.log('Evaluating Alogrithm')
|
||||
const tmp = evaluate(algo, gcodeParams)
|
||||
if (typeof tmp === 'number') {
|
||||
price = tmp.toFixed(2)
|
||||
} else {
|
||||
@ -150,11 +204,11 @@ export const post: APIRoute = async ({ request }) => {
|
||||
details: 'It seems the algorithm resolution failed',
|
||||
algorithm: algo,
|
||||
algorithmError: 'Algorithm return a Unit',
|
||||
parameters: params
|
||||
parameters: gcodeParams
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
console.dir(e)
|
||||
logger.dir(e)
|
||||
return buildRFC7807({
|
||||
type: '/algorithm-error',
|
||||
status: 500,
|
||||
@ -162,11 +216,11 @@ export const post: APIRoute = async ({ request }) => {
|
||||
details: 'It seems the algorithm resolution failed',
|
||||
algorithm: algo,
|
||||
algorithmError: e,
|
||||
parameters: params
|
||||
parameters: gcodeParams
|
||||
})
|
||||
}
|
||||
}
|
||||
console.log('request successfull :)', file)
|
||||
logger.log('request successfull :)')
|
||||
return {
|
||||
status: 200,
|
||||
body: JSON.stringify({
|
||||
|
@ -0,0 +1,26 @@
|
||||
import { objectOmit } from '@dzeio/object-util'
|
||||
import type { APIRoute } from 'astro'
|
||||
import { buildRFC7807 } from '../../../../../../../libs/RFCs/RFC7807'
|
||||
import DaoFactory from '../../../../../../../models/DaoFactory'
|
||||
|
||||
export const get: APIRoute = async ({ params, request }) => {
|
||||
const userId = params.userId as string
|
||||
const configId = params.configId as string
|
||||
const fileName = params.fileName as string
|
||||
|
||||
|
||||
const dao = await DaoFactory.get('config').get(configId)
|
||||
|
||||
if (!dao) {
|
||||
return buildRFC7807({
|
||||
title: 'Config does not exists :('
|
||||
})
|
||||
}
|
||||
|
||||
const file = dao.files.find((it) => it.name === fileName)
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: file?.data
|
||||
}
|
||||
}
|
44
src/pages/api/users/[userId]/configs/index.ts
Normal file
44
src/pages/api/users/[userId]/configs/index.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { objectOmit } from '@dzeio/object-util'
|
||||
import type { APIRoute } from 'astro'
|
||||
import { buildRFC7807 } from '../../../../../libs/RFCs/RFC7807'
|
||||
import DaoFactory from '../../../../../models/DaoFactory'
|
||||
|
||||
export const post: APIRoute = async ({ params, request }) => {
|
||||
const userId = params.userId as string
|
||||
|
||||
const body = request.body
|
||||
|
||||
if (!body) {
|
||||
return buildRFC7807({
|
||||
title: 'Missing config file'
|
||||
})
|
||||
}
|
||||
|
||||
const reader = body.getReader()
|
||||
|
||||
const chunks: Array<Uint8Array> = []
|
||||
|
||||
let finished= false
|
||||
do {
|
||||
const { done, value } = await reader.read()
|
||||
finished = done
|
||||
if (value) {
|
||||
chunks.push(value)
|
||||
}
|
||||
} while (!finished)
|
||||
|
||||
const buffer = Buffer.concat(chunks)
|
||||
|
||||
const dao = await DaoFactory.get('config').create({
|
||||
user: userId,
|
||||
type: 'prusa',
|
||||
files: [{
|
||||
name: 'config.ini',
|
||||
data: buffer
|
||||
}]
|
||||
})
|
||||
return {
|
||||
status: 201,
|
||||
body: JSON.stringify(objectOmit(dao ?? {}, 'files'))
|
||||
}
|
||||
}
|
@ -1,8 +1,14 @@
|
||||
import type { APIRoute } from 'astro'
|
||||
import crypto from 'node:crypto'
|
||||
import { validateAuth } from '../../../../../libs/validateAuth'
|
||||
import DaoFactory from '../../../../../models/DaoFactory'
|
||||
|
||||
export const post: APIRoute = async ({ params, request }) => {
|
||||
validateAuth(request, {
|
||||
name: 'keys.create',
|
||||
cookie: true,
|
||||
api: false
|
||||
})
|
||||
const userId = params.userId as string
|
||||
|
||||
const dao = await DaoFactory.get('apiKey').create({
|
||||
|
Reference in New Issue
Block a user