mirror of
https://github.com/kou029w/_.git
synced 2025-01-30 22:08:02 +00:00
delete frourio project
This commit is contained in:
parent
98b4ecf114
commit
4a4a56578c
53 changed files with 0 additions and 13587 deletions
|
@ -1,5 +0,0 @@
|
|||
node_modules
|
||||
.next
|
||||
dist
|
||||
server/migration
|
||||
server/index.js
|
|
@ -1,38 +0,0 @@
|
|||
module.exports = {
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:react/recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:@typescript-eslint/eslint-recommended',
|
||||
'plugin:prettier/recommended',
|
||||
'prettier/@typescript-eslint'
|
||||
],
|
||||
plugins: ['@typescript-eslint', 'react'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
es6: true
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect'
|
||||
}
|
||||
},
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaFeatures: {
|
||||
jsx: true
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
'react/react-in-jsx-scope': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off'
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.js'],
|
||||
rules: { '@typescript-eslint/no-var-requires': ['off'] }
|
||||
}
|
||||
]
|
||||
}
|
40
frourio/.gitignore
vendored
40
frourio/.gitignore
vendored
|
@ -1,40 +0,0 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
# server
|
||||
server/**/$*.ts
|
||||
server/**/*.db
|
||||
server/index.js
|
||||
server/database.json
|
||||
server/.upload
|
||||
server/public/icons/*
|
||||
!server/public/icons/dammy.svg
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"semi": false,
|
||||
"trailingComma": "none",
|
||||
"singleQuote": true
|
||||
}
|
3
frourio/.vscode/extensions.json
vendored
3
frourio/.vscode/extensions.json
vendored
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"recommendations": ["dbaeumer.vscode-eslint", "prisma.prisma"]
|
||||
}
|
7
frourio/.vscode/settings.json
vendored
7
frourio/.vscode/settings.json
vendored
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"eslint.run": "onSave",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
},
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/import?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
|
@ -1,6 +0,0 @@
|
|||
require('dotenv').config({ path: 'server/.env' })
|
||||
|
||||
module.exports = {
|
||||
input: 'server/api',
|
||||
baseURL: `${process.env.API_ORIGIN || ''}${process.env.BASE_PATH || ''}`
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
import { useState, useCallback, ChangeEvent } from 'react'
|
||||
import styles from '~/styles/UserBanner.module.css'
|
||||
import { apiClient } from '~/utils/apiClient'
|
||||
import { UserInfo } from '$/types'
|
||||
|
||||
const UserBanner = () => {
|
||||
const [isLoggedIn, setIsLoggedIn] = useState(false)
|
||||
const [token, setToken] = useState('')
|
||||
const [userInfo, setUserInfo] = useState({} as UserInfo)
|
||||
|
||||
const editIcon = useCallback(
|
||||
async (e: ChangeEvent<HTMLInputElement>) => {
|
||||
if (!e.target.files?.length) return
|
||||
|
||||
setUserInfo(
|
||||
await apiClient.user.$post({
|
||||
headers: { token },
|
||||
body: { icon: e.target.files[0] }
|
||||
})
|
||||
)
|
||||
},
|
||||
[token]
|
||||
)
|
||||
|
||||
const login = useCallback(async () => {
|
||||
const id = prompt('Enter the user id (See server/.env)')
|
||||
const pass = prompt('Enter the user pass (See server/.env)')
|
||||
if (!id || !pass) return alert('Login failed')
|
||||
|
||||
let newToken = ''
|
||||
|
||||
try {
|
||||
newToken = (await apiClient.token.$post({ body: { id, pass } })).token
|
||||
setToken(newToken)
|
||||
} catch (e) {
|
||||
return alert('Login failed')
|
||||
}
|
||||
|
||||
setUserInfo(await apiClient.user.$get({ headers: { token: newToken } }))
|
||||
setIsLoggedIn(true)
|
||||
}, [])
|
||||
|
||||
const logout = useCallback(async () => {
|
||||
await apiClient.token.delete({ headers: { token } })
|
||||
setToken('')
|
||||
setIsLoggedIn(false)
|
||||
}, [token])
|
||||
|
||||
return (
|
||||
<div className={styles.userBanner}>
|
||||
{isLoggedIn ? (
|
||||
<div>
|
||||
<img src={userInfo.icon} className={styles.userIcon} />
|
||||
<span>{userInfo.name}</span>
|
||||
<input type="file" accept="image/*" onChange={editIcon} />
|
||||
<button onClick={logout}>LOGOUT</button>
|
||||
</div>
|
||||
) : (
|
||||
<button onClick={login}>LOGIN</button>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default UserBanner
|
|
@ -1,10 +0,0 @@
|
|||
const { pathsToModuleNameMapper } = require('ts-jest/utils')
|
||||
const { compilerOptions } = require('./tsconfig')
|
||||
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, {
|
||||
prefix: '<rootDir>/'
|
||||
})
|
||||
}
|
2
frourio/next-env.d.ts
vendored
2
frourio/next-env.d.ts
vendored
|
@ -1,2 +0,0 @@
|
|||
/// <reference types="next" />
|
||||
/// <reference types="next/types/global" />
|
|
@ -1,54 +0,0 @@
|
|||
{
|
||||
"name": "frourio",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "npm run migrate:up && run-p dev:*",
|
||||
"dev:client": "next dev -p 3000",
|
||||
"dev:server": "npm run dev --prefix server",
|
||||
"dev:aspida": "aspida --watch",
|
||||
"build": "run-p build:client build:server",
|
||||
"build:client": "aspida && next build && next export",
|
||||
"build:server": "npm run build --prefix server",
|
||||
"build:types": "aspida && npm run build:frourio --prefix server",
|
||||
"lint": "eslint --ext .ts,.js,.tsx .",
|
||||
"lint:fix": "npm run lint -- --fix",
|
||||
"migrate": "npm run migrate:save && npm run migrate:up",
|
||||
"migrate:save": "npm run migrate:save --prefix server",
|
||||
"migrate:up": "npm run migrate:up --prefix server",
|
||||
"migrate:down": "npm run migrate:down --prefix server",
|
||||
"start": "run-p start:*",
|
||||
"start:client": "next start",
|
||||
"start:server": "npm start --prefix server",
|
||||
"test": "npm run build:types && jest",
|
||||
"typecheck": "npm run build:types && tsc --noEmit && tsc --noEmit -p server"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aspida/fetch": "^0.10.2",
|
||||
"@aspida/swr": "^0.2.2",
|
||||
"class-validator": "^0.12.2",
|
||||
"next": "^10.0.1",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1",
|
||||
"swr": "^0.3.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^26.0.14",
|
||||
"@types/node": "^14.11.2",
|
||||
"@types/react": "^16.9.56",
|
||||
"@typescript-eslint/eslint-plugin": "^4.6.1",
|
||||
"@typescript-eslint/parser": "^4.6.1",
|
||||
"cross-env": "^7.0.2",
|
||||
"dotenv": "^8.2.0",
|
||||
"eslint": "^7.13.0",
|
||||
"eslint-config-prettier": "^6.15.0",
|
||||
"eslint-plugin-prettier": "^3.1.4",
|
||||
"eslint-plugin-react": "^7.21.5",
|
||||
"jest": "^26.6.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.1.2",
|
||||
"ts-jest": "^26.4.3",
|
||||
"ts-loader": "^8.0.10",
|
||||
"typescript": "^4.0.5"
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
import { AppProps } from 'next/app'
|
||||
import '../styles/globals.css'
|
||||
|
||||
function MyApp({ Component, pageProps }: AppProps) {
|
||||
return <Component {...pageProps} />
|
||||
}
|
||||
|
||||
export default MyApp
|
|
@ -1,100 +0,0 @@
|
|||
import Head from 'next/head'
|
||||
import { useCallback, useState, FormEvent, ChangeEvent } from 'react'
|
||||
import useAspidaSWR from '@aspida/swr'
|
||||
import styles from '~/styles/Home.module.css'
|
||||
import { apiClient } from '~/utils/apiClient'
|
||||
import { Task } from '$prisma/client'
|
||||
import UserBanner from '~/components/UserBanner'
|
||||
|
||||
const Home = () => {
|
||||
const { data: tasks, error, mutate: setTasks } = useAspidaSWR(apiClient.tasks)
|
||||
const [label, setLabel] = useState('')
|
||||
const inputLavel = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => setLabel(e.target.value),
|
||||
[]
|
||||
)
|
||||
|
||||
const createTask = useCallback(
|
||||
async (e: FormEvent) => {
|
||||
e.preventDefault()
|
||||
if (!label) return
|
||||
|
||||
await apiClient.tasks.post({ body: { label } })
|
||||
setLabel('')
|
||||
setTasks(await apiClient.tasks.$get())
|
||||
},
|
||||
[label]
|
||||
)
|
||||
|
||||
const toggleDone = useCallback(async (task: Task) => {
|
||||
await apiClient.tasks._taskId(task.id).patch({ body: { done: !task.done } })
|
||||
setTasks(await apiClient.tasks.$get())
|
||||
}, [])
|
||||
|
||||
const deleteTask = useCallback(async (task: Task) => {
|
||||
await apiClient.tasks._taskId(task.id).delete()
|
||||
setTasks(await apiClient.tasks.$get())
|
||||
}, [])
|
||||
|
||||
if (error) return <div>failed to load</div>
|
||||
if (!tasks) return <div>loading...</div>
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Head>
|
||||
<title>frourio-todo-app</title>
|
||||
<link rel="icon" href="/favicon.png" />
|
||||
</Head>
|
||||
|
||||
<main className={styles.main}>
|
||||
<UserBanner />
|
||||
|
||||
<h1 className={styles.title}>
|
||||
Welcome to <a href="https://nextjs.org">Next.js!</a>
|
||||
</h1>
|
||||
|
||||
<p className={styles.description}>frourio-todo-app</p>
|
||||
|
||||
<div>
|
||||
<form style={{ textAlign: 'center' }} onSubmit={createTask}>
|
||||
<input value={label} type="text" onChange={inputLavel} />
|
||||
<input type="submit" value="ADD" />
|
||||
</form>
|
||||
<ul className={styles.tasks}>
|
||||
{tasks.map((task) => (
|
||||
<li key={task.id}>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={task.done}
|
||||
onChange={() => toggleDone(task)}
|
||||
/>
|
||||
<span>{task.label}</span>
|
||||
</label>
|
||||
<input
|
||||
type="button"
|
||||
value="DELETE"
|
||||
style={{ float: 'right' }}
|
||||
onClick={() => deleteTask(task)}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer className={styles.footer}>
|
||||
<a
|
||||
href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Powered by{' '}
|
||||
<img src="/vercel.svg" alt="Vercel Logo" className={styles.logo} />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Home
|
Binary file not shown.
Before Width: | Height: | Size: 1.6 KiB |
|
@ -1,4 +0,0 @@
|
|||
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.1 KiB |
|
@ -1,5 +0,0 @@
|
|||
SERVER_PORT=8080
|
||||
BASE_PATH=/api
|
||||
API_ORIGIN=http://localhost:8080
|
||||
USER_ID=id
|
||||
USER_PASS=pass
|
|
@ -1,5 +0,0 @@
|
|||
import { defineController } from './$relay'
|
||||
|
||||
export default defineController(() => ({
|
||||
get: () => ({ status: 200, body: 'Hello, world!' })
|
||||
}))
|
|
@ -1,5 +0,0 @@
|
|||
export type Methods = {
|
||||
get: {
|
||||
resBody: string
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
import { defineController } from './$relay'
|
||||
import { updateTask, deleteTask } from '$/service/tasks'
|
||||
|
||||
export default defineController(() => ({
|
||||
patch: async ({ body, params }) => {
|
||||
await updateTask(params.taskId, body)
|
||||
return { status: 204 }
|
||||
},
|
||||
delete: async ({ params }) => {
|
||||
await deleteTask(params.taskId)
|
||||
return { status: 204 }
|
||||
}
|
||||
}))
|
|
@ -1,11 +0,0 @@
|
|||
import { Task } from '$prisma/client'
|
||||
|
||||
export type Methods = {
|
||||
patch: {
|
||||
reqBody: Partial<Pick<Task, 'label' | 'done'>>
|
||||
status: 204
|
||||
}
|
||||
delete: {
|
||||
status: 204
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
import { defineController } from './$relay'
|
||||
import { getTasks, createTask } from '$/service/tasks'
|
||||
|
||||
const print = (text: string) => console.log(text)
|
||||
|
||||
export default defineController({ getTasks, print }, ({ getTasks, print }) => ({
|
||||
get: async ({ query }) => {
|
||||
if (query?.message) print(query.message)
|
||||
|
||||
return { status: 200, body: await getTasks(query?.limit) }
|
||||
},
|
||||
post: async ({ body }) => ({
|
||||
status: 201,
|
||||
body: await createTask(body.label)
|
||||
})
|
||||
}))
|
|
@ -1,16 +0,0 @@
|
|||
import { Task } from '$prisma/client'
|
||||
|
||||
export type Methods = {
|
||||
get: {
|
||||
query?: {
|
||||
limit?: number
|
||||
message?: string
|
||||
}
|
||||
|
||||
resBody: Task[]
|
||||
}
|
||||
post: {
|
||||
reqBody: Pick<Task, 'label'>
|
||||
resBody: Task
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
import { defineController } from './$relay'
|
||||
import { validateUser, createToken, deleteToken } from '$/service/user'
|
||||
|
||||
export default defineController(() => ({
|
||||
post: ({ body }) =>
|
||||
validateUser(body.id, body.pass)
|
||||
? { status: 201, body: { token: createToken() } }
|
||||
: { status: 401 },
|
||||
|
||||
delete: ({ headers }) => {
|
||||
deleteToken(headers.token)
|
||||
return { status: 204 }
|
||||
}
|
||||
}))
|
|
@ -1,14 +0,0 @@
|
|||
import { LoginBody, TokenHeader } from '$/validators'
|
||||
|
||||
export type Methods = {
|
||||
post: {
|
||||
reqBody: LoginBody
|
||||
resBody: {
|
||||
token: string
|
||||
}
|
||||
}
|
||||
|
||||
delete: {
|
||||
reqHeaders: TokenHeader
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
import { defineController } from './$relay'
|
||||
import { getUserInfoById, changeIcon } from '$/service/user'
|
||||
|
||||
export default defineController(() => ({
|
||||
get: ({ user }) => ({ status: 200, body: getUserInfoById(user.id) }),
|
||||
post: async ({ user, body }) => ({
|
||||
status: 201,
|
||||
body: await changeIcon(user.id, body.icon)
|
||||
})
|
||||
}))
|
|
@ -1,27 +0,0 @@
|
|||
import { defineHooks } from './$relay'
|
||||
import { getUserIdByToken } from '$/service/user'
|
||||
|
||||
export type AdditionalRequest = {
|
||||
user: {
|
||||
id: string
|
||||
}
|
||||
}
|
||||
|
||||
export default defineHooks((fastify) => ({
|
||||
preHandler: fastify.auth([
|
||||
(req, _, done) => {
|
||||
const user =
|
||||
typeof req.headers.token === 'string' &&
|
||||
getUserIdByToken(req.headers.token)
|
||||
|
||||
if (user) {
|
||||
// eslint-disable-next-line
|
||||
// @ts-expect-error
|
||||
req.user = user
|
||||
done()
|
||||
} else {
|
||||
done(new Error('Unauthorized'))
|
||||
}
|
||||
}
|
||||
])
|
||||
}))
|
|
@ -1,16 +0,0 @@
|
|||
import { TokenHeader } from '$/validators'
|
||||
import { UserInfo } from '$/types'
|
||||
|
||||
export type Methods = {
|
||||
get: {
|
||||
reqHeaders: TokenHeader
|
||||
resBody: UserInfo
|
||||
}
|
||||
|
||||
post: {
|
||||
reqHeaders: TokenHeader
|
||||
reqFormat: FormData
|
||||
reqBody: { icon: Blob }
|
||||
resBody: UserInfo
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
import path from 'path'
|
||||
import Fastify from 'fastify'
|
||||
import helmet from 'fastify-helmet'
|
||||
import cors from 'fastify-cors'
|
||||
import fastifyStatic from 'fastify-static'
|
||||
import fastifyAuth from 'fastify-auth'
|
||||
import { SERVER_PORT, BASE_PATH } from './service/envValues'
|
||||
import server from './$server'
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(helmet)
|
||||
fastify.register(cors)
|
||||
fastify.register(fastifyStatic, {
|
||||
root: path.join(__dirname, 'public'),
|
||||
prefix: BASE_PATH
|
||||
})
|
||||
fastify.register(fastifyAuth).after(() => {
|
||||
server(fastify, { basePath: BASE_PATH })
|
||||
})
|
||||
fastify.listen(SERVER_PORT)
|
|
@ -1,50 +0,0 @@
|
|||
{
|
||||
"name": "frourio-server",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "npm run migrate:up && run-p dev:*",
|
||||
"dev:server": "webpack --watch --mode=development",
|
||||
"dev:frourio": "frourio --watch",
|
||||
"dev:prisma": "prisma generate --watch",
|
||||
"build": "npm run build:frourio && webpack --mode=production",
|
||||
"build:frourio": "npm run migrate:up && prisma generate && frourio",
|
||||
"migrate": "npm run migrate:save && npm run migrate:up",
|
||||
"migrate:save": "prisma migrate save --create-db --experimental",
|
||||
"migrate:up": "prisma migrate up --create-db --experimental",
|
||||
"migrate:down": "prisma migrate down --experimental",
|
||||
"pm2:start": "pm2 start pm2.config.json --env production",
|
||||
"pm2:stop": "pm2 stop pm2.config.json",
|
||||
"pm2:delete": "pm2 delete pm2.config.json",
|
||||
"pm2:logs": "pm2 logs",
|
||||
"pm2:monit": "pm2 monit",
|
||||
"start": "cross-env NODE_ENV=production node index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "^2.8.0",
|
||||
"class-validator": "^0.12.2",
|
||||
"dotenv": "^8.2.0",
|
||||
"fastify": "^3.7.0",
|
||||
"fastify-auth": "^1.0.1",
|
||||
"fastify-cors": "^4.1.0",
|
||||
"fastify-helmet": "^5.0.3",
|
||||
"fastify-multipart": "^3.3.0",
|
||||
"fastify-static": "^3.3.0",
|
||||
"pm2": "^4.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@prisma/cli": "^2.8.0",
|
||||
"@types/busboy": "^0.2.3",
|
||||
"cross-env": "^7.0.2",
|
||||
"frourio": "^0.19.1",
|
||||
"nodemon-webpack-plugin": "^4.3.2",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"ts-loader": "^8.0.10",
|
||||
"ts-node": "^9.0.0",
|
||||
"tsconfig-paths-webpack-plugin": "^3.3.0",
|
||||
"typescript": "^4.0.5",
|
||||
"webpack": "^4.44.2",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"webpack-node-externals": "^2.5.2"
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"name": "frourio",
|
||||
"script": "index.js",
|
||||
"env_production": {
|
||||
"NODE_ENV": "production"
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
DATABASE_URL=file:DATABASE_FILE
|
|
@ -1,41 +0,0 @@
|
|||
# Migration `20201001130532`
|
||||
|
||||
This migration has been generated by solufa at 10/1/2020, 10:05:32 PM.
|
||||
You can check out the [state of the schema](./schema.prisma) after the migration.
|
||||
|
||||
## Database Steps
|
||||
|
||||
```sql
|
||||
CREATE TABLE `Task` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`label` varchar(191) NOT NULL ,
|
||||
`done` boolean NOT NULL DEFAULT false,
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
|
||||
```
|
||||
|
||||
## Changes
|
||||
|
||||
```diff
|
||||
diff --git schema.prisma schema.prisma
|
||||
migration ..20201001130532
|
||||
--- datamodel.dml
|
||||
+++ datamodel.dml
|
||||
@@ -1,0 +1,14 @@
|
||||
+datasource db {
|
||||
+ provider = "sqlite"
|
||||
+ url = "***"
|
||||
+}
|
||||
+
|
||||
+generator client {
|
||||
+ provider = "prisma-client-js"
|
||||
+}
|
||||
+
|
||||
+model Task {
|
||||
+ id Int @id @default(autoincrement())
|
||||
+ label String
|
||||
+ done Boolean @default(false)
|
||||
+}
|
||||
```
|
||||
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
datasource db {
|
||||
provider = "sqlite"
|
||||
url = "***"
|
||||
}
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
model Task {
|
||||
id Int @id @default(autoincrement())
|
||||
label String
|
||||
done Boolean @default(false)
|
||||
}
|
|
@ -1,113 +0,0 @@
|
|||
{
|
||||
"version": "0.3.14-fixed",
|
||||
"steps": [
|
||||
{
|
||||
"tag": "CreateSource",
|
||||
"source": "db"
|
||||
},
|
||||
{
|
||||
"tag": "CreateArgument",
|
||||
"location": {
|
||||
"tag": "Source",
|
||||
"source": "db"
|
||||
},
|
||||
"argument": "provider",
|
||||
"value": "\"sqlite\""
|
||||
},
|
||||
{
|
||||
"tag": "CreateArgument",
|
||||
"location": {
|
||||
"tag": "Source",
|
||||
"source": "db"
|
||||
},
|
||||
"argument": "url",
|
||||
"value": "\"***\""
|
||||
},
|
||||
{
|
||||
"tag": "CreateModel",
|
||||
"model": "Task"
|
||||
},
|
||||
{
|
||||
"tag": "CreateField",
|
||||
"model": "Task",
|
||||
"field": "id",
|
||||
"type": "Int",
|
||||
"arity": "Required"
|
||||
},
|
||||
{
|
||||
"tag": "CreateDirective",
|
||||
"location": {
|
||||
"path": {
|
||||
"tag": "Field",
|
||||
"model": "Task",
|
||||
"field": "id"
|
||||
},
|
||||
"directive": "id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "CreateDirective",
|
||||
"location": {
|
||||
"path": {
|
||||
"tag": "Field",
|
||||
"model": "Task",
|
||||
"field": "id"
|
||||
},
|
||||
"directive": "default"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "CreateArgument",
|
||||
"location": {
|
||||
"tag": "Directive",
|
||||
"path": {
|
||||
"tag": "Field",
|
||||
"model": "Task",
|
||||
"field": "id"
|
||||
},
|
||||
"directive": "default"
|
||||
},
|
||||
"argument": "",
|
||||
"value": "autoincrement()"
|
||||
},
|
||||
{
|
||||
"tag": "CreateField",
|
||||
"model": "Task",
|
||||
"field": "label",
|
||||
"type": "String",
|
||||
"arity": "Required"
|
||||
},
|
||||
{
|
||||
"tag": "CreateField",
|
||||
"model": "Task",
|
||||
"field": "done",
|
||||
"type": "Boolean",
|
||||
"arity": "Required"
|
||||
},
|
||||
{
|
||||
"tag": "CreateDirective",
|
||||
"location": {
|
||||
"path": {
|
||||
"tag": "Field",
|
||||
"model": "Task",
|
||||
"field": "done"
|
||||
},
|
||||
"directive": "default"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "CreateArgument",
|
||||
"location": {
|
||||
"tag": "Directive",
|
||||
"path": {
|
||||
"tag": "Field",
|
||||
"model": "Task",
|
||||
"field": "done"
|
||||
},
|
||||
"directive": "default"
|
||||
},
|
||||
"argument": "",
|
||||
"value": "false"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
# Prisma Migrate lockfile v1
|
||||
|
||||
20201001130532
|
|
@ -1,14 +0,0 @@
|
|||
datasource db {
|
||||
provider = "sqlite"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
model Task {
|
||||
id Int @id @default(autoincrement())
|
||||
label String
|
||||
done Boolean @default(false)
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512">
|
||||
<style type="text/css">
|
||||
.st0{fill:#4B4B4B;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M256,265.308c73.252,0,132.644-59.391,132.644-132.654C388.644,59.412,329.252,0,256,0
|
||||
c-73.262,0-132.643,59.412-132.643,132.654C123.357,205.917,182.738,265.308,256,265.308z" style="fill: rgb(75, 75, 75);"></path>
|
||||
<path class="st0" d="M425.874,393.104c-5.922-35.474-36-84.509-57.552-107.465c-5.829-6.212-15.948-3.628-19.504-1.427
|
||||
c-27.04,16.672-58.782,26.399-92.819,26.399c-34.036,0-65.778-9.727-92.818-26.399c-3.555-2.201-13.675-4.785-19.505,1.427
|
||||
c-21.55,22.956-51.628,71.991-57.551,107.465C71.573,480.444,164.877,512,256,512C347.123,512,440.427,480.444,425.874,393.104z" style="fill: rgb(75, 75, 75);"></path>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 839 B |
|
@ -1,11 +0,0 @@
|
|||
import dotenv from 'dotenv'
|
||||
|
||||
dotenv.config()
|
||||
|
||||
const USER_ID = process.env.USER_ID ?? ''
|
||||
const USER_PASS = process.env.USER_PASS ?? ''
|
||||
const SERVER_PORT = +(process.env.SERVER_PORT ?? '8080')
|
||||
const BASE_PATH = process.env.BASE_PATH ?? ''
|
||||
const API_ORIGIN = process.env.API_ORIGIN ?? ''
|
||||
|
||||
export { USER_ID, USER_PASS, SERVER_PORT, BASE_PATH, API_ORIGIN }
|
|
@ -1,20 +0,0 @@
|
|||
import { PrismaClient } from '@prisma/client'
|
||||
import { Task, TaskUpdateInput } from '$prisma/client'
|
||||
import { depend } from 'velona'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
export const getTasks = depend(
|
||||
{ prisma: prisma as { task: { findMany(): Promise<Task[]> } } },
|
||||
async ({ prisma }, limit?: number) =>
|
||||
(await prisma.task.findMany()).slice(0, limit)
|
||||
)
|
||||
|
||||
export const createTask = (label: Task['label']) =>
|
||||
prisma.task.create({ data: { label } })
|
||||
|
||||
export const updateTask = (id: Task['id'], partialTask: TaskUpdateInput) =>
|
||||
prisma.task.update({ where: { id }, data: partialTask })
|
||||
|
||||
export const deleteTask = (id: Task['id']) =>
|
||||
prisma.task.delete({ where: { id } })
|
|
@ -1,51 +0,0 @@
|
|||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { Multipart } from 'fastify-multipart'
|
||||
import { API_ORIGIN, BASE_PATH, USER_ID, USER_PASS } from './envValues'
|
||||
|
||||
const iconsDir = 'public/icons'
|
||||
const createIconURL = (name: string) =>
|
||||
`${API_ORIGIN}${BASE_PATH}/icons/${name}`
|
||||
const userInfo = {
|
||||
name: 'sample user',
|
||||
icon: createIconURL(
|
||||
fs
|
||||
.readdirSync(path.resolve(iconsDir))
|
||||
.filter((n) => n !== 'dammy.svg')
|
||||
.pop() ?? 'dammy.svg'
|
||||
)
|
||||
}
|
||||
|
||||
let userToken: string | null = null
|
||||
|
||||
export const validateUser = (id: string, pass: string) =>
|
||||
id === USER_ID && pass === USER_PASS
|
||||
|
||||
export const validateToken = (token: string) =>
|
||||
userToken !== null && token === userToken
|
||||
|
||||
export const getUserIdByToken = (token: string) =>
|
||||
validateToken(token) && { id: USER_ID }
|
||||
|
||||
export const getUserInfoById = (id: string) => ({ id, ...userInfo })
|
||||
|
||||
export const createToken = () => {
|
||||
userToken = `token:${Date.now()}`
|
||||
return userToken
|
||||
}
|
||||
|
||||
export const deleteToken = (token: string) => {
|
||||
if (validateToken(token)) userToken = null
|
||||
}
|
||||
|
||||
export const changeIcon = async (id: string, iconFile: Multipart) => {
|
||||
const iconName = `${Date.now()}${path.extname(iconFile.filename)}`
|
||||
|
||||
await fs.promises.writeFile(
|
||||
path.resolve(iconsDir, iconName),
|
||||
await iconFile.toBuffer()
|
||||
)
|
||||
|
||||
userInfo.icon = createIconURL(iconName)
|
||||
return { id, ...userInfo }
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
import controller from '$/api/tasks/controller'
|
||||
import { getTasks } from '$/service/tasks'
|
||||
|
||||
test('dependency injection into controller', async () => {
|
||||
let printedMessage = ''
|
||||
|
||||
const injectedController = controller.inject({
|
||||
getTasks: getTasks.inject({
|
||||
prisma: {
|
||||
task: {
|
||||
findMany: () =>
|
||||
Promise.resolve([
|
||||
{ id: 0, label: 'task1', done: false },
|
||||
{ id: 1, label: 'task2', done: false },
|
||||
{ id: 2, label: 'task3', done: true },
|
||||
{ id: 3, label: 'task4', done: true },
|
||||
{ id: 4, label: 'task5', done: false }
|
||||
])
|
||||
}
|
||||
}
|
||||
}),
|
||||
print: (text: string) => {
|
||||
printedMessage = text
|
||||
}
|
||||
})()
|
||||
|
||||
const limit = 3
|
||||
const message = 'test message'
|
||||
const res = await injectedController.get({
|
||||
query: { limit, message }
|
||||
})
|
||||
|
||||
expect(res.body).toHaveLength(limit)
|
||||
expect(printedMessage).toBe(message)
|
||||
})
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"downlevelIteration": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": ["dom"],
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"$/*": ["./*"],
|
||||
"$prisma/*": ["./node_modules/.prisma/*"]
|
||||
},
|
||||
"rootDir": ".",
|
||||
"strict": true,
|
||||
"strictPropertyInitialization": false,
|
||||
"target": "es6"
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
export type UserInfo = {
|
||||
id: string
|
||||
name: string
|
||||
icon: string
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
import { MinLength, IsString } from 'class-validator'
|
||||
|
||||
export class LoginBody {
|
||||
@MinLength(2)
|
||||
id: string
|
||||
|
||||
@MinLength(4)
|
||||
pass: string
|
||||
}
|
||||
|
||||
export class TokenHeader {
|
||||
@IsString()
|
||||
@MinLength(10)
|
||||
token: string
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin')
|
||||
const nodeExternals = require('webpack-node-externals')
|
||||
const NodemonPlugin = require('nodemon-webpack-plugin')
|
||||
|
||||
module.exports = {
|
||||
entry: './index.ts',
|
||||
target: 'node',
|
||||
node: {
|
||||
__dirname: false
|
||||
},
|
||||
output: {
|
||||
filename: 'index.js',
|
||||
path: __dirname
|
||||
},
|
||||
module: {
|
||||
rules: [{ test: /\.ts$/, loader: 'ts-loader' }]
|
||||
},
|
||||
plugins: [new NodemonPlugin()],
|
||||
resolve: {
|
||||
extensions: ['.ts', '.js'],
|
||||
plugins: [new TsconfigPathsPlugin()]
|
||||
},
|
||||
externals: [nodeExternals()]
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,80 +0,0 @@
|
|||
.container {
|
||||
min-height: 100vh;
|
||||
padding: 0 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.main {
|
||||
padding: 5rem 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.footer {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
border-top: 1px solid #eaeaea;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.footer img {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.title a {
|
||||
color: #0070f3;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.title a:hover,
|
||||
.title a:focus,
|
||||
.title a:active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
line-height: 1.15;
|
||||
font-size: 4rem;
|
||||
}
|
||||
|
||||
.title,
|
||||
.description {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.description {
|
||||
line-height: 1.5;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.tasks {
|
||||
width: 300px;
|
||||
padding: 0;
|
||||
margin: 20px auto 0;
|
||||
list-style-type: none;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.tasks > li {
|
||||
margin-top: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
.userBanner {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.userIcon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background: #ddd;
|
||||
vertical-align: bottom;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
|
||||
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"~/*": ["./*"],
|
||||
"$/*": ["./server/*"],
|
||||
"$prisma/*": ["./server/node_modules/.prisma/*"]
|
||||
},
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"strict": false
|
||||
},
|
||||
"exclude": ["node_modules", "server"],
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
import aspida from '@aspida/fetch'
|
||||
import api from '~/server/api/$api'
|
||||
|
||||
export const apiClient = api(aspida())
|
7449
frourio/yarn.lock
7449
frourio/yarn.lock
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue