Skip to content

Добавить новый пользовательский функционал #443

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 18 commits into
base: notifications-tg
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/api/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,5 @@ package-lock.json
# IDE files
/.idea

#uploads
src/uploads/avatars
5 changes: 4 additions & 1 deletion apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
"dependencies": {
"@diary-spo/crypto": "workspace:*",
"@elysiajs/cors": "^1.1.1",
"@elysiajs/static": "^1.1.1",
"@types/cli-progress": "^3.11.6",
"@types/node-telegram-bot-api": "^0.64.7",
"cache-manager": "^5.7.6",
"cli-progress": "^3.12.0",
"elysia": "1.1.21",
"elysia-compression": "^0.0.7",
"elysia-helmet": "^2.0.0",
Expand All @@ -34,7 +37,7 @@
"devDependencies": {
"@types/node-rsa": "^1.1.4",
"@diary-spo/shared": "workspace:*",
"@elysiajs/swagger": "^1.1.5",
"@elysiajs/swagger": "^1.1.6",
"@types/pg": "^8.11.10"
}
}
4 changes: 4 additions & 0 deletions apps/api/src/helpers/crutches.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const crutchesInit = () => {
// @ts-ignore
BigInt.prototype.toJSON = function() { return this.toString() }
}
109 changes: 109 additions & 0 deletions apps/api/src/helpers/syncDatabaseForDecorations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { readdir } from 'node:fs/promises'
import cliProgress from 'cli-progress'
import { AvatarModel } from '../models/Avatar'
import { AvatarTagModel } from '../models/AvatarTag'
import { TagModel } from '../models/Tag'

const pathToDecorationsFile = 'src/uploads/decorations.json'
const pathToAvatars = 'src/uploads/avatars'

interface Content {
avatars: AvatarContent[]
}

interface AvatarContent {
isAnimated: boolean
filename: string
tags: string[]
price: number
}

export const syncDatabaseForDecorations = async () => {
console.log('Обновляю декорации в базе данных...')

const progress = 0
const progressBar = new cliProgress.SingleBar(
{
format: ' {bar} | {filename} | {value}/{total}'
},
cliProgress.Presets.shades_classic
)

const file = Bun.file(pathToDecorationsFile)

if (!(await file.exists())) {
console.log('Файл декораций не найден. Пропускаю ...')
return
}

const contents: Content = await file.json()
const avatarFiles = await readdir(pathToAvatars)

progressBar.start(avatarFiles.length, progress)

for (const avatarFile of avatarFiles) {
progressBar.increment(1, { filename: avatarFile })
const avatarToSave = {
filename: avatarFile,
isAnimated: avatarFile.endsWith('.gif'),
price: 1000
}

let tags: string[] = []

// Пробуем найти, переопределена ли цена и статус анимации
for (const avatarInfo of contents.avatars) {
if (avatarInfo.filename !== avatarFile) continue
avatarToSave.isAnimated = avatarInfo.isAnimated
avatarToSave.price = avatarInfo.price
tags = avatarInfo.tags
break
}

// Находим или создаём модель
const avatarModel = await AvatarModel.findOrCreate({
where: {
filename: avatarFile
},
defaults: avatarToSave
})

// Проверяем наличие тегов
if (!tags)
await AvatarTagModel.destroy({
where: {
avatarId: avatarModel[0].id
}
})
else
for (const tag of tags) {
const tagModel = await TagModel.findOrCreate({
where: {
value: tag
},
defaults: {
value: tag
}
})
await AvatarTagModel.findOrCreate({
where: {
avatarId: avatarModel[0].id,
tagId: tagModel[0].id
},
defaults: {
avatarId: avatarModel[0].id,
tagId: tagModel[0].id
}
})
}

// Если создана - то завершаем цикл
if (avatarModel[1]) continue

await avatarModel[0].update(avatarToSave)
}

progressBar.stop()

console.log('Обновил все декорации')
}
9 changes: 8 additions & 1 deletion apps/api/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ import { Elysia } from 'elysia'
import { compression } from 'elysia-compression'
import { helmet } from 'elysia-helmet'

import { BOT_TOKEN, TIMEZONE } from '@config'
import { TIMEZONE } from '@config'
import { sequelize } from '@db'

import { getTimezone } from './config/getTimeZone'
import { routes } from './routes'

import './models/relations'
import { syncDatabaseForDecorations } from './helpers/syncDatabaseForDecorations'
import {crutchesInit} from "./helpers/crutches";

// Подключаем костыли
crutchesInit()

// настраиваем сервер...
const port = Bun.env.PORT ?? 3003
Expand Down Expand Up @@ -69,6 +74,8 @@ console.log(
}.`
)

await syncDatabaseForDecorations()

export type App = typeof app
const workerURL = new URL('worker', import.meta.url).href
new Worker(workerURL)
Expand Down
1 change: 1 addition & 0 deletions apps/api/src/models/Avatar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './model'
42 changes: 42 additions & 0 deletions apps/api/src/models/Avatar/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { DataTypes } from 'sequelize'

import { cache, enableCache, sequelize } from '@db'

import { SPOModel } from '../SPO'
import type { IModelPrototype } from '../types'

// REMOVE IT
// ?
export type AvatarModelType = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

уже есть такой тип в shared

id: number
filename: string
price: number
isAnimated: boolean
}

export type IAvatarModelType = IModelPrototype<AvatarModelType, 'id'>

const avatarModel = sequelize.define<IAvatarModelType>('avatar', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
filename: {
type: DataTypes.STRING(35),
allowNull: false
},
price: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 1000
},
isAnimated: {
type: DataTypes.BOOLEAN,
allowNull: false
}
})

export const AvatarModel = enableCache
? cache.init<IAvatarModelType>(avatarModel)
: avatarModel
1 change: 1 addition & 0 deletions apps/api/src/models/AvatarTag/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './model'
39 changes: 39 additions & 0 deletions apps/api/src/models/AvatarTag/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { DataTypes } from 'sequelize'

import { cache, enableCache, sequelize } from '@db'

import { AvatarModel } from '../Avatar'
import { TagModel } from '../Tag'
import type { IModelPrototypeNoId } from '../types'

// REMOVE IT
// ?
export type AvatarTagModelType = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

вынести в shared, если ещё не там (если есть необходимость использовать на фронте)

avatarId: bigint
tagId: bigint
}

export type IAvatarTagModelType = IModelPrototypeNoId<AvatarTagModelType>

const avatarTagModel = sequelize.define<IAvatarTagModelType>('avatarTag', {
avatarId: {
type: DataTypes.BIGINT,
primaryKey: true,
allowNull: false,
references: {
model: AvatarModel
}
},
tagId: {
type: DataTypes.BIGINT,
primaryKey: true,
allowNull: false,
references: {
model: TagModel
}
}
})

export const AvatarTagModel = enableCache
? cache.init<IAvatarTagModelType>(avatarTagModel)
: avatarTagModel
1 change: 1 addition & 0 deletions apps/api/src/models/BalanceOperation/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './model'
56 changes: 56 additions & 0 deletions apps/api/src/models/BalanceOperation/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { DataTypes } from 'sequelize'

import { cache, enableCache, sequelize } from '@db'

import type {IModelPrototype} from '../types'
import {Nullable} from "@diary-spo/shared";
import {DiaryUserModel} from "../DiaryUser";

export type BalanceOperationModelType = {
id: bigint
diaryUserId: bigint
senderId: Nullable<bigint>
comment: Nullable<string>
amount: number
datetime?: string
}

export type IBalanceOperationModelType = IModelPrototype<BalanceOperationModelType, 'id'>

const balanceOperationModel = sequelize.define<IBalanceOperationModelType>('balanceOperation', {
id: {
type: DataTypes.BIGINT,
primaryKey: true,
autoIncrement: true
},
senderId: {
type: DataTypes.BIGINT,
allowNull: true,
references: {
model: DiaryUserModel
}
},
diaryUserId: {
type: DataTypes.BIGINT,
references: {
model: DiaryUserModel
}
},
comment: {
type: DataTypes.STRING,
allowNull: true
},
amount: {
type: DataTypes.INTEGER,
allowNull: false
},
datetime: {
type: DataTypes.DATEONLY,
allowNull: false,
defaultValue: Date.now()
}
})

export const BalanceOperationModel = enableCache
? cache.init<IBalanceOperationModelType>(balanceOperationModel)
: balanceOperationModel
9 changes: 9 additions & 0 deletions apps/api/src/models/DiaryUser/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { KEY } from '@config'
import { sequelize } from '@db'
import { formatDate } from '@utils'

import { AvatarModel } from '../Avatar'
import { GroupModel } from '../Group'
import type { IModelPrototype } from '../types'

Expand All @@ -26,6 +27,7 @@ export type DiaryUserModelType = {
termStartDate?: Nullable<string>
isAdmin: boolean
idFromDiary: number
avatarId: Nullable<number>
}

export type IDiaryUserModel = IModelPrototype<DiaryUserModelType, 'id'>
Expand Down Expand Up @@ -125,6 +127,13 @@ export const DiaryUserModel = sequelize.define<IDiaryUserModel>('diaryUser', {
defaultValue: false,
comment: 'Признак администратора'
},
avatarId: {
type: DataTypes.INTEGER,
allowNull: true,
references: {
model: AvatarModel
}
},
idFromDiary: {
type: DataTypes.INTEGER,
allowNull: false,
Expand Down
1 change: 1 addition & 0 deletions apps/api/src/models/Tag/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './model'
31 changes: 31 additions & 0 deletions apps/api/src/models/Tag/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { DataTypes } from 'sequelize'

import { cache, enableCache, sequelize } from '@db'

import type { IModelPrototype } from '../types'

// REMOVE IT
// ?
export type TagModelType = {
id: bigint
value: string
}

export type ITagModelType = IModelPrototype<TagModelType, 'id'>

const tagModel = sequelize.define<ITagModelType>('tag', {
id: {
type: DataTypes.BIGINT,
primaryKey: true,
autoIncrement: true,
allowNull: false
},
value: {
type: DataTypes.STRING,
allowNull: false
}
})

export const TagModel = enableCache
? cache.init<ITagModelType>(tagModel)
: tagModel
1 change: 1 addition & 0 deletions apps/api/src/models/UserAvatar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './model'
Loading
Loading