Skip to content

Commit

Permalink
Merge pull request #913 from undb-xyz/release/v0.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
nichenqin committed May 3, 2023
2 parents ee83e16 + 2ae5ef9 commit 136a55b
Show file tree
Hide file tree
Showing 585 changed files with 11,296 additions and 16,686 deletions.
13 changes: 5 additions & 8 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,15 @@ jobs:
steps:
- name: Check out code
uses: actions/checkout@v3
with:
fetch-depth: 2

- uses: pnpm/action-setup@v2.2.4
with:
version: 8.1.0

- name: Setup Node.js environment
uses: actions/setup-node@v3
with:
node-version: 18
cache: 'pnpm'
node-version: 18.16.0

- uses: pnpm/action-setup@v2.2.4
with:
version: 8.3.1

- name: Install dependencies
run: pnpm install
Expand Down
3 changes: 2 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"esbenp.prettier-vscode",
"rangav.vscode-thunder-client",
"ms-azuretools.vscode-docker",
"alexcvzz.vscode-sqlite"
"alexcvzz.vscode-sqlite",
"bierner.lit-html"
]
}
9 changes: 7 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,14 @@ COPY --from=builder /undb/out/ .

RUN pnpm install -r --offline

ARG PUBLIC_UNDB_ADMIN_EMAIL
ARG PUBLIC_UNDB_ADMIN_PASSWORD

ENV NODE_ENV production
RUN pnpm run build --filter=backend --filter=frontend
RUN pnpm prune --prod --config.ignore-scripts=true

RUN rm -rf ./node_modules
RUN HUSKY=0 pnpm install -r --prod

# runner
FROM gcr.io/distroless/nodejs18-debian11 as runner
Expand All @@ -36,6 +41,6 @@ ENV UNDB_DATABASE_SQLITE_DATA /var/opt/.undb
COPY --from=installer /undb/node_modules ./node_modules
COPY --from=installer /undb/packages ./packages
COPY --from=installer /undb/apps/backend ./apps/backend
COPY --from=installer /undb/apps/frontend/dist ./out
COPY --from=installer /undb/apps/frontend/build ./out

CMD ["apps/backend/dist/main.js"]
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ docker run -d --name undb -p 4000:4000 --platform linux/x86_64 -v ~/.undb/:/var/

> You'll need a render account to deploy your own undb instance
![Alt](https://repobeats.axiom.co/api/embed/4e19a26c5f110e58bbcce4bb6a79c144a481c3dd.svg "Repobeats analytics image")

## License

undb is open-source under the GNU Affero General Public License Version 3 (AGPLv3). You can find it [here](./LICENSE).
41 changes: 22 additions & 19 deletions apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@
"name": "@undb/backend",
"version": "0.0.0",
"dependencies": {
"@mikro-orm/better-sqlite": "^5.6.15",
"@mikro-orm/core": "^5.6.15",
"@mikro-orm/migrations": "^5.6.15",
"@mikro-orm/better-sqlite": "^5.7.4",
"@mikro-orm/core": "^5.7.4",
"@mikro-orm/migrations": "^5.7.4",
"@mikro-orm/nestjs": "^5.1.8",
"@nestjs/common": "^9.3.12",
"@nestjs/common": "^9.4.0",
"@nestjs/config": "^2.3.1",
"@nestjs/core": "^9.3.12",
"@nestjs/core": "^9.4.0",
"@nestjs/cqrs": "^9.0.3",
"@nestjs/jwt": "^10.0.3",
"@nestjs/passport": "^9.0.3",
"@nestjs/platform-express": "^9.3.12",
"@nestjs/platform-express": "^9.4.0",
"@nestjs/serve-static": "^3.0.1",
"@nestjs/terminus": "^9.2.2",
"@trpc/server": "^10.18.0",
"@trpc/server": "^10.23.0",
"@undb/core": "^0.0.0",
"@undb/cqrs": "^0.0.0",
"@undb/domain": "^0.0.0",
Expand All @@ -26,12 +26,13 @@
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"compression": "^1.7.4",
"helmet": "^6.0.1",
"i18next": "^22.4.14",
"cookie-parser": "^1.4.6",
"helmet": "^6.1.5",
"i18next": "^22.4.15",
"i18next-http-middleware": "^3.3.0",
"joi": "^17.9.1",
"joi": "^17.9.2",
"nestjs-cls": "^3.3.1",
"nestjs-pino": "^3.1.2",
"nestjs-pino": "^3.2.0",
"oxide.ts": "^1.1.0",
"passport": "^0.6.0",
"passport-jwt": "^4.0.1",
Expand All @@ -40,29 +41,31 @@
"pino-pretty": "^10.0.0",
"reflect-metadata": "^0.1.13",
"rimraf": "^5.0.0",
"rxjs": "^7.8.0",
"rxjs": "^7.8.1",
"uuid": "^9.0.0"
},
"devDependencies": {
"@nestjs/cli": "^9.3.0",
"@nestjs/cli": "^9.4.2",
"@nestjs/schematics": "^9.1.0",
"@nestjs/testing": "^9.3.12",
"@nestjs/testing": "^9.4.0",
"@swc/cli": "^0.1.62",
"@swc/core": "^1.3.44",
"@swc/core": "^1.3.56",
"@types/bcrypt": "^5.0.0",
"@types/compression": "^1.7.2",
"@types/cookie-parser": "^1.4.3",
"@types/express": "^4.17.17",
"@types/jest": "^29.5.0",
"@types/jest": "^29.5.1",
"@types/multer": "^1.4.7",
"@types/node": "^18.15.11",
"@types/node": "^18.16.3",
"@types/passport": "^1.0.12",
"@types/passport-jwt": "^3.0.8",
"@types/passport-local": "^1.0.35",
"@types/supertest": "^2.0.12",
"@types/uuid": "^9.0.1",
"@undb/eslint-config": "^0.0.0",
"eslint": "^8.37.0",
"eslint": "^8.39.0",
"esm": "^3.2.25",
"express": "^4.18.2",
"jest": "^29.5.0",
"nodemon": "^2.0.22",
"npm-run-all": "^4.1.5",
Expand All @@ -72,7 +75,7 @@
"ts-node": "^10.9.1",
"tsconfig": "^0.0.0",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.0.3"
"typescript": "^5.0.4"
},
"jest": {
"moduleFileExtensions": [
Expand Down
6 changes: 4 additions & 2 deletions apps/backend/src/attachment/adapters/local-object-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ export class LocalObjectStorage implements IObjectStorage {
return path.join(p, token + '_' + name)
}

async put(buffer: Buffer, originalname: string): Promise<{ token: string; id: string }> {
async put(buffer: Buffer, originalname: string): Promise<{ url: string; token: string; id: string }> {
const nestedPath = this.#nestedPath
const p = await this.#getPath(nestedPath)
const id = v4()
const token = path.join(nestedPath, id)
const full = this.#getFull(p, id, originalname)
await fs.promises.writeFile(full, buffer)
return { token, id }

const url = `/public/${token}_${originalname}`
return { token, id, url }
}
}
2 changes: 1 addition & 1 deletion apps/backend/src/attachment/adapters/object-storage.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export interface IObjectStorage {
put(buffer: Buffer, originalname: string): Promise<{ token: string; id: string }>
put(buffer: Buffer, originalname: string): Promise<{ url: string; token: string; id: string }>
}
3 changes: 2 additions & 1 deletion apps/backend/src/attachment/attachment.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ export class AttachmentController {
}),
)
async upload(@UploadedFile() file: Express.Multer.File): Promise<AttachmentResponseDto> {
const { token, id } = await this.attachmentService.uploadFile(file.buffer, file.originalname)
const { url, token, id } = await this.attachmentService.uploadFile(file.buffer, file.originalname)

return plainToClass(AttachmentResponseDto, {
name: file.originalname,
size: file.size,
mimeType: file.mimetype,
id,
token,
url,
})
}
}
2 changes: 1 addition & 1 deletion apps/backend/src/attachment/attachment.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { InjectObjectStorage } from './adapters/provider.js'
export class AttachmentService {
constructor(@InjectObjectStorage() private readonly storage: IObjectStorage) {}

public async uploadFile(buffer: Buffer, originalname: string): Promise<{ token: string; id: string }> {
public async uploadFile(buffer: Buffer, originalname: string): Promise<{ url: string; token: string; id: string }> {
return this.storage.put(buffer, originalname)
}
}
29 changes: 24 additions & 5 deletions apps/backend/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Body, Controller, Get, HttpCode, HttpStatus, Post, Request, UseGuards } from '@nestjs/common'
import { Body, Controller, Get, HttpCode, HttpStatus, Post, Put, Request, Res, UseGuards } from '@nestjs/common'
import { JwtService } from '@nestjs/jwt'
import type { Response } from 'express'
import { AuthService } from './auth.service.js'
import { JwtAuthGuard } from './jwt-auth.guard.js'
import { LocalAuthGuard } from './local-auth.guard.js'
Expand All @@ -10,17 +11,28 @@ export class AuthController {

@HttpCode(HttpStatus.OK)
@Post('register')
async register(@Body() body: { password: string; email: string }) {
async register(@Body() body: { password: string; email: string }, @Res({ passthrough: true }) res: Response) {
const payload = await this.authService.register(body.email, body.password)
return { access_token: this.jwtService.sign(payload) }
const token = this.jwtService.sign(payload)
res.cookie('undb_auth', token)
return { access_token: token }
}

@HttpCode(HttpStatus.OK)
@UseGuards(LocalAuthGuard)
@Post('login')
async login(@Request() req: Express.Request) {
async login(@Request() req: Express.Request, @Res({ passthrough: true }) res: Response) {
const payload = await this.authService.login(req.user as any)
return { access_token: this.jwtService.sign(payload) }
const token = this.jwtService.sign(payload)
res.cookie('undb_auth', token)
return { access_token: token }
}

@HttpCode(HttpStatus.OK)
@Post('logout')
async logout(@Res({ passthrough: true }) res: Response) {
res.clearCookie('undb_auth')
return { access_token: null }
}

@HttpCode(HttpStatus.OK)
Expand All @@ -29,4 +41,11 @@ export class AuthController {
getProfile(@Request() req: Express.Request) {
return this.authService.me(req.user as any)
}

@HttpCode(HttpStatus.OK)
@UseGuards(JwtAuthGuard)
@Put('me')
updateMyProfile(@Request() req: Express.Request, @Body() body: { username: string; avatar: string }) {
return this.authService.updateProfile((req.user as any).userId, body)
}
}
8 changes: 6 additions & 2 deletions apps/backend/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ import { authConfig } from '../configs/auth.config.js'
import { UserModule } from '../modules/user/user.module.js'
import { AuthController } from './auth.controller.js'
import { AuthService } from './auth.service.js'
import { NestLgoinCommandHandler, NestRegisterCommandHandler } from './commands/index.js'
import {
NestLgoinCommandHandler,
NestRegisterCommandHandler,
NestUpdateProfileCommandHandler,
} from './commands/index.js'
import { JwtStrategy } from './jwt.strategy.js'
import { LocalStrategy } from './local.strategy.js'
import { NestGetMeQueryHandler } from './queries/index.js'

const CommandHandlers = [NestLgoinCommandHandler, NestRegisterCommandHandler]
const CommandHandlers = [NestLgoinCommandHandler, NestRegisterCommandHandler, NestUpdateProfileCommandHandler]
const QueryHandlers = [NestGetMeQueryHandler]

@Module({
Expand Down
6 changes: 5 additions & 1 deletion apps/backend/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Injectable } from '@nestjs/common'
import { CommandBus, QueryBus } from '@nestjs/cqrs'
import { IQueryUser, WithUserEmail } from '@undb/core'
import { GetMeQuery, LoginCommand, RegisterCommand } from '@undb/cqrs'
import { GetMeQuery, LoginCommand, RegisterCommand, UpdateProfileCommand } from '@undb/cqrs'
import * as bcrypt from 'bcrypt'
import { UserService } from '../modules/user/user.service.js'
import { InvalidPassword } from './errors/invalid-password.error.js'
Expand Down Expand Up @@ -40,4 +40,8 @@ export class AuthService {
async me(user: IQueryUser) {
return this.queryBus.execute(new GetMeQuery({ me: user }))
}

async updateProfile(userId: string, profile: { username?: string; avatar?: string | null }) {
return this.commandBus.execute(new UpdateProfileCommand({ userId, ...profile }))
}
}
1 change: 1 addition & 0 deletions apps/backend/src/auth/commands/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './login.command.handler.js'
export * from './register.command.handler.js'
export * from './update-profile.command.handler.js'
11 changes: 11 additions & 0 deletions apps/backend/src/auth/commands/update-profile.command.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { CommandHandler } from '@nestjs/cqrs'
import type { IUserRepository } from '@undb/core'
import { UpdateProfileCommand, UpdateProfileCommandHandler } from '@undb/cqrs'
import { InjectUserRepository } from '../../modules/user/adapters/index.js'

@CommandHandler(UpdateProfileCommand)
export class NestUpdateProfileCommandHandler extends UpdateProfileCommandHandler {
constructor(@InjectUserRepository() protected readonly repo: IUserRepository) {
super(repo)
}
}
7 changes: 6 additions & 1 deletion apps/backend/src/auth/jwt.strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'
import { type ConfigType } from '@nestjs/config'
import { PassportStrategy } from '@nestjs/passport'
import { ClsStore } from '@undb/core'
import type { Request } from 'express'
import { ClsService } from 'nestjs-cls'
import { ExtractJwt, Strategy } from 'passport-jwt'
import { InjectAuthConfig, authConfig } from '../configs/auth.config.js'
Expand All @@ -10,12 +11,16 @@ import { InjectAuthConfig, authConfig } from '../configs/auth.config.js'
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(@InjectAuthConfig() config: ConfigType<typeof authConfig>, private readonly cls: ClsService<ClsStore>) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
jwtFromRequest: ExtractJwt.fromExtractors([JwtStrategy.extractJWT, ExtractJwt.fromAuthHeaderAsBearerToken()]),
ignoreExpiration: false,
secretOrKey: config.jwt.secret,
})
}

private static extractJWT(req: Request): string | null {
return req.cookies?.['undb_auth'] ?? null
}

async validate(payload: any) {
this.cls.set('user.userId', payload.sub)
return { userId: payload.sub, email: payload.email }
Expand Down
6 changes: 3 additions & 3 deletions apps/backend/src/configs/auth.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ export const authConfig = registerAs('auth', () => ({
secret: process.env.UNDB_JWT_SECRET!,
},
admin: {
email: process.env.UNDB_ADMIN_EMAIL,
password: process.env.UNDB_ADMIN_PASSWORD,
username: process.env.UNDB_ADMIN_USERNAME,
email: process.env.PUBLIC_UNDB_ADMIN_EMAIL,
password: process.env.PUBLIC_UNDB_ADMIN_PASSWORD,
username: process.env.PUBLIC_UNDB_ADMIN_USERNAME,
},
}))
2 changes: 2 additions & 0 deletions apps/backend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { HttpAdapterHost, NestFactory } from '@nestjs/core'
import * as trpcExpress from '@trpc/server/adapters/express'
import { AppRouter } from '@undb/trpc'
import compression from 'compression'
import cookieParser from 'cookie-parser'
import { Request } from 'express'
import helmet from 'helmet'
import { ClsMiddleware, ClsService } from 'nestjs-cls'
Expand Down Expand Up @@ -36,6 +37,7 @@ async function bootstrap() {
const cls = app.get(ClsService)

app
.use(cookieParser())
.use(
new ClsMiddleware({
generateId: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { TableSqliteRepository } from '@undb/sqlite'
import { Option } from 'oxide.ts'
@Injectable()
export class NestTableSqliteRepository extends TableSqliteRepository {
constructor(public readonly orm: MikroORM, public readonly em: EntityManager) {
super(em)
constructor(public readonly orm: MikroORM) {
super(orm.em as EntityManager)
}

@UseRequestContext()
Expand Down
13 changes: 13 additions & 0 deletions apps/frontend/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example

# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock
Loading

0 comments on commit 136a55b

Please sign in to comment.