Compare commits
2 Commits
ed9eb93013
...
cf2eb88662
Author | SHA1 | Date | |
---|---|---|---|
|
cf2eb88662 | ||
|
9723c825f7 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
.env
|
.env
|
||||||
node_modules/
|
node_modules/
|
||||||
|
dist/
|
||||||
|
13
Dockerfile
Normal file
13
Dockerfile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
FROM 'node:20'
|
||||||
|
|
||||||
|
RUN mkdir -p /usr/src/app/dist
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
COPY package.json /usr/src/app/
|
||||||
|
COPY package-lock.json /usr/src/app/
|
||||||
|
COPY dist /usr/src/app/dist
|
||||||
|
|
||||||
|
RUN npm ci --omit=dev
|
||||||
|
EXPOSE 3003
|
||||||
|
|
||||||
|
CMD [ "npm", "run", "up:prod" ]
|
4
d-script/restart.sh
Normal file
4
d-script/restart.sh
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
docker stop bh-mongo;
|
||||||
|
docker volume rm bh-mongo-volume;
|
||||||
|
docker volume create bh-mongo-volume;
|
||||||
|
sh d-script/up-mongo.sh;
|
@ -5,6 +5,6 @@ docker \
|
|||||||
--name bh-mongo \
|
--name bh-mongo \
|
||||||
-e MONGO_INITDB_ROOT_USERNAME=qqq \
|
-e MONGO_INITDB_ROOT_USERNAME=qqq \
|
||||||
-e MONGO_INITDB_ROOT_PASSWORD=qqq \
|
-e MONGO_INITDB_ROOT_PASSWORD=qqq \
|
||||||
-p 27017:27017 \
|
-p 8888:27017 \
|
||||||
-v bh-mongo-volume:/data/db \
|
-v bh-mongo-volume:/data/db \
|
||||||
mongo:8.0.3;
|
mongo:8.0.3;
|
||||||
|
15
docker-compose.yml
Normal file
15
docker-compose.yml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
bh:
|
||||||
|
# build: .
|
||||||
|
image: brojs/todo/bh:$TAG
|
||||||
|
restart: always
|
||||||
|
env_file: ./.env
|
||||||
|
ports:
|
||||||
|
- 3003:3003
|
||||||
|
environment:
|
||||||
|
- PORT=${PORT}
|
||||||
|
- JWT_SECRET=${JWT_SECRET}
|
||||||
|
- MONGO_CONNECT_URL=${MONGO_CONNECT_URL}
|
||||||
|
|
3110
package-lock.json
generated
3110
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -14,16 +14,13 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"express": "^5.0.1",
|
"express": "^5.0.1",
|
||||||
"express-json-validator-middleware": "^3.0.1",
|
|
||||||
"install": "^0.13.0",
|
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"npm": "^10.9.1",
|
"mongoose": "^8.8.3",
|
||||||
"pbkdf2-password": "^1.2.1",
|
"pbkdf2-password": "^1.2.1"
|
||||||
"ts-node": "^10.9.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^5.0.0",
|
"@types/express": "^5.0.0",
|
||||||
"nodemon": "^3.1.7",
|
"ts-node": "^10.9.2",
|
||||||
"ts-node-dev": "^2.0.0",
|
"ts-node-dev": "^2.0.0",
|
||||||
"typescript": "^5.7.2"
|
"typescript": "^5.7.2"
|
||||||
}
|
}
|
||||||
|
29
src/connect.ts
Normal file
29
src/connect.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import mongoose from "mongoose";
|
||||||
|
|
||||||
|
import ItemListModel from "./model/todo-list";
|
||||||
|
import ItemModel from "./model/todo-item";
|
||||||
|
|
||||||
|
export const connect = async () => {
|
||||||
|
await mongoose.connect(process.env.MONGO_CONNECT_URL!);
|
||||||
|
console.log("Connected to database");
|
||||||
|
|
||||||
|
const lists = await ItemListModel.find();
|
||||||
|
|
||||||
|
console.log(JSON.stringify(lists, null, 4))
|
||||||
|
|
||||||
|
if (lists.length === 0) {
|
||||||
|
await ItemListModel.create({
|
||||||
|
name: "Test List",
|
||||||
|
});
|
||||||
|
|
||||||
|
const item = await ItemModel.create({
|
||||||
|
title: "Test Item",
|
||||||
|
});
|
||||||
|
|
||||||
|
lists.forEach(async (list) => {
|
||||||
|
await (list as unknown as any).addItem(item);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Database initiated");
|
||||||
|
};
|
17
src/main.ts
17
src/main.ts
@ -1,8 +1,9 @@
|
|||||||
import express, { json } from 'express';
|
import express, { json } from 'express';
|
||||||
import { handleError } from './utils/errorHandler'
|
|
||||||
import 'dotenv/config'
|
import 'dotenv/config'
|
||||||
|
|
||||||
import { router } from './routes'
|
import { router } from './routes'
|
||||||
|
import { handleError } from './utils/errorHandler'
|
||||||
|
import { connect } from './connect';
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
@ -13,6 +14,14 @@ app.use(json({ limit: '100kb' }))
|
|||||||
app.use(router)
|
app.use(router)
|
||||||
|
|
||||||
app.use(handleError)
|
app.use(handleError)
|
||||||
app.listen(port, () => {
|
|
||||||
console.log(`App is running on port http://localhost:${port}`);
|
const start = async () => {
|
||||||
})
|
console.log('starting...')
|
||||||
|
await connect()
|
||||||
|
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`App is running on port http://localhost:${port}`);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
start()
|
||||||
|
24
src/model/todo-item.ts
Normal file
24
src/model/todo-item.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { Schema, model } from 'mongoose'
|
||||||
|
|
||||||
|
const schema = new Schema({
|
||||||
|
title: {type: String, required: true },
|
||||||
|
description: String,
|
||||||
|
created: { type: Date, default: () => new Date().toISOString() },
|
||||||
|
done: { type: Boolean, default: false },
|
||||||
|
// createdBy: { type: Schema.Types.ObjectId, required: true, ref: 'User' }
|
||||||
|
deleted: { type: Boolean, default: false }
|
||||||
|
})
|
||||||
|
|
||||||
|
schema.virtual('id').get(function () {
|
||||||
|
return this._id.toHexString()
|
||||||
|
})
|
||||||
|
|
||||||
|
schema.set('toJSON', {
|
||||||
|
virtuals: true,
|
||||||
|
versionKey: false,
|
||||||
|
transform: (doc, ret) => {
|
||||||
|
delete ret._id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default model('Item', schema)
|
34
src/model/todo-list.ts
Normal file
34
src/model/todo-list.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { Schema, model } from 'mongoose'
|
||||||
|
|
||||||
|
const schema = new Schema({
|
||||||
|
name: String,
|
||||||
|
items: [{ type: Schema.Types.ObjectId, required: true, ref: 'Item' }],
|
||||||
|
created: { type: Date, default: () => new Date().toISOString() },
|
||||||
|
// createdBy: { type: Schema.Types.ObjectId, required: true, ref: 'User' }
|
||||||
|
deleted: { type: Boolean, default: false }
|
||||||
|
})
|
||||||
|
|
||||||
|
schema.virtual('id').get(function () {
|
||||||
|
return this._id.toHexString()
|
||||||
|
})
|
||||||
|
|
||||||
|
schema.set('toJSON', {
|
||||||
|
virtuals: true,
|
||||||
|
versionKey: false,
|
||||||
|
transform: (doc, ret) => {
|
||||||
|
delete ret._id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
schema.method('addItem', async function(item) {
|
||||||
|
this.items.push(item._id)
|
||||||
|
return await this.save()
|
||||||
|
})
|
||||||
|
|
||||||
|
schema.method('removeItem', async function(item) {
|
||||||
|
this.items = this.items.filter(i => i !== item._id)
|
||||||
|
return await this.save()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
export default model('TodoList', schema)
|
@ -3,9 +3,11 @@ import { Router } from "express";
|
|||||||
import pkg from '../../package.json'
|
import pkg from '../../package.json'
|
||||||
|
|
||||||
import { router as usersRouter } from './users'
|
import { router as usersRouter } from './users'
|
||||||
|
import { router as todoRouter } from './todo'
|
||||||
|
|
||||||
export const router = Router();
|
export const router = Router();
|
||||||
|
|
||||||
router.get('/healthcheck', (req, res) => void res.send({ ok: true, version: pkg.version }));
|
router.get('/healthcheck', (req, res) => void res.send({ ok: true, version: pkg.version }));
|
||||||
|
|
||||||
router.use('/users', usersRouter)
|
router.use('/users', usersRouter)
|
||||||
|
router.use('/todo', todoRouter)
|
||||||
|
66
src/routes/todo/index.ts
Normal file
66
src/routes/todo/index.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
import ListsModel from '../../model/todo-list';
|
||||||
|
import ItemModel from '../../model/todo-item';
|
||||||
|
|
||||||
|
export const router = Router();
|
||||||
|
|
||||||
|
router.get('/lists', async (req, res) => {
|
||||||
|
const lists = await ListsModel.find({});
|
||||||
|
|
||||||
|
res.json(lists);
|
||||||
|
})
|
||||||
|
|
||||||
|
router.post('/list', async (req, res) => {
|
||||||
|
const { name } = req.body
|
||||||
|
const list = await ListsModel.create({
|
||||||
|
name
|
||||||
|
});
|
||||||
|
|
||||||
|
res.json(list);
|
||||||
|
})
|
||||||
|
|
||||||
|
router.delete('/item/:itemId', async (req, res) => {
|
||||||
|
const { itemId } = req.params;
|
||||||
|
|
||||||
|
const item = await ItemModel.findById(itemId);
|
||||||
|
|
||||||
|
if (!item) throw new Error('Item not found');
|
||||||
|
|
||||||
|
await ItemModel.findByIdAndDelete(itemId);
|
||||||
|
|
||||||
|
res.send(item);
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get('/list/:listId', async (req, res) => {
|
||||||
|
const { listId } = req.params;
|
||||||
|
|
||||||
|
const list = await ListsModel
|
||||||
|
.findById(listId)
|
||||||
|
.populate('items')
|
||||||
|
.exec();
|
||||||
|
|
||||||
|
if (!list) throw new Error('List not found');
|
||||||
|
|
||||||
|
res.json(list);
|
||||||
|
})
|
||||||
|
|
||||||
|
router.post('/:listId/item', async (req, res) => {
|
||||||
|
const { listId } = req.params
|
||||||
|
const { title, description = '' } = req.body
|
||||||
|
|
||||||
|
const list = await ListsModel.findById(listId);
|
||||||
|
|
||||||
|
if (!list) {
|
||||||
|
throw new Error('List not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const item = await ItemModel.create({
|
||||||
|
title,
|
||||||
|
description
|
||||||
|
});
|
||||||
|
|
||||||
|
await (list as any).addItem(item);
|
||||||
|
|
||||||
|
res.send(item)
|
||||||
|
})
|
||||||
|
|
@ -1,7 +1,5 @@
|
|||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
import { Validator } from "express-json-validator-middleware";
|
|
||||||
import bkfd2Password from "pbkdf2-password";
|
import bkfd2Password from "pbkdf2-password";
|
||||||
import { promisify } from 'node:util'
|
|
||||||
|
|
||||||
import jwt from 'jsonwebtoken'
|
import jwt from 'jsonwebtoken'
|
||||||
|
|
||||||
@ -12,8 +10,6 @@ const hasher = bkfd2Password();
|
|||||||
|
|
||||||
export const router = Router();
|
export const router = Router();
|
||||||
|
|
||||||
const { validate } = new Validator({});
|
|
||||||
|
|
||||||
const user = {
|
const user = {
|
||||||
type: "object",
|
type: "object",
|
||||||
required: ["name"],
|
required: ["name"],
|
||||||
|
Loading…
Reference in New Issue
Block a user