mirror of
https://github.com/hcengineering/platform.git
synced 2025-03-19 05:08:12 +00:00
parent
6ae1289623
commit
94061c6489
@ -30,6 +30,7 @@ import notification, {
|
||||
} from '@hcengineering/notification'
|
||||
import { DOMAIN_PREFERENCE } from '@hcengineering/preference'
|
||||
import contact, { type PersonSpace } from '@hcengineering/contact'
|
||||
import chunter from '@hcengineering/chunter'
|
||||
|
||||
import { DOMAIN_DOC_NOTIFY, DOMAIN_NOTIFICATION, DOMAIN_USER_NOTIFY } from './index'
|
||||
import { DOMAIN_SPACE } from '@hcengineering/model-core'
|
||||
@ -322,6 +323,26 @@ export const notificationOperation: MigrateOperation = {
|
||||
{ objectSpace: contact.space.Contacts }
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
state: 'migrate-wrong-spaces-v1',
|
||||
func: async () => {
|
||||
await client.update<DocNotifyContext>(
|
||||
DOMAIN_DOC_NOTIFY,
|
||||
{ _class: notification.class.DocNotifyContext, objectClass: chunter.class.DirectMessage },
|
||||
{ objectSpace: core.space.Space }
|
||||
)
|
||||
await client.update<DocNotifyContext>(
|
||||
DOMAIN_DOC_NOTIFY,
|
||||
{ _class: notification.class.DocNotifyContext, objectClass: chunter.class.Channel },
|
||||
{ objectSpace: core.space.Space }
|
||||
)
|
||||
await client.update<DocNotifyContext>(
|
||||
DOMAIN_DOC_NOTIFY,
|
||||
{ _class: notification.class.DocNotifyContext, objectClass: 'recruit:class:Vacancy' as any },
|
||||
{ objectSpace: core.space.Space }
|
||||
)
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
|
@ -148,13 +148,14 @@
|
||||
return result
|
||||
}
|
||||
|
||||
function getValue (name: string, type: Type<any>): string {
|
||||
function getValue (name: string, type: Type<any>, attrClass: Ref<Class<Doc>>): string {
|
||||
const presenter = hierarchy.classHierarchyMixin(attrClass, view.mixin.AttributePresenter)?.presenter
|
||||
if (presenter !== undefined) {
|
||||
return name
|
||||
}
|
||||
if (hierarchy.isDerived(type._class, core.class.RefTo)) {
|
||||
return '$lookup.' + name
|
||||
}
|
||||
// if (hierarchy.isDerived(type._class, core.class.ArrOf)) {
|
||||
// return getValue(name, (type as ArrOf<any>).of)
|
||||
// }
|
||||
return name
|
||||
}
|
||||
|
||||
@ -162,14 +163,14 @@
|
||||
if (attribute.hidden === true || attribute.label === undefined) return
|
||||
if (viewlet.configOptions?.hiddenKeys?.includes(attribute.name)) return
|
||||
if (hierarchy.isDerived(attribute.type._class, core.class.Collection)) return
|
||||
const value = getValue(attribute.name, attribute.type)
|
||||
const { attrClass, category } = getAttributePresenterClass(hierarchy, attribute)
|
||||
const value = getValue(attribute.name, attribute.type, attrClass)
|
||||
for (const res of result) {
|
||||
const key = typeof res.value === 'string' ? res.value : res.value?.key
|
||||
if (key === undefined) return
|
||||
if (key === attribute.name) return
|
||||
if (key === value) return
|
||||
}
|
||||
const { attrClass, category } = getAttributePresenterClass(hierarchy, attribute)
|
||||
const mixin =
|
||||
category === 'object'
|
||||
? view.mixin.ObjectPresenter
|
||||
|
@ -898,6 +898,7 @@ export async function createAcc (
|
||||
first: string,
|
||||
last: string,
|
||||
confirmed: boolean = false,
|
||||
shouldConfirm: boolean = true,
|
||||
extra?: Record<string, string>
|
||||
): Promise<Account> {
|
||||
const email = cleanEmail(_email)
|
||||
@ -933,7 +934,7 @@ export async function createAcc (
|
||||
throw new PlatformError(new Status(Severity.ERROR, platform.status.AccountAlreadyExists, { account: email }))
|
||||
}
|
||||
const sesURL = getMetadata(accountPlugin.metadata.SES_URL)
|
||||
if (!confirmed) {
|
||||
if (!confirmed && shouldConfirm) {
|
||||
if (sesURL !== undefined && sesURL !== '') {
|
||||
await sendConfirmation(productId, branding, newAccount)
|
||||
} else {
|
||||
@ -994,7 +995,7 @@ export async function signUpOtp (
|
||||
const first = email.split('@', 1)[0] ?? ''
|
||||
const last = ''
|
||||
|
||||
await createAcc(ctx, db, productId, branding, email, null, first, last, false)
|
||||
await createAcc(ctx, db, productId, branding, email, null, first, last, false, false)
|
||||
|
||||
return await sendOtp(ctx, db, productId, branding, _email)
|
||||
}
|
||||
@ -2525,7 +2526,7 @@ export async function joinWithProvider (
|
||||
await useInvite(db, inviteId)
|
||||
return result
|
||||
}
|
||||
const newAccount = await createAcc(ctx, db, productId, branding, email, null, first, last, true, extra)
|
||||
const newAccount = await createAcc(ctx, db, productId, branding, email, null, first, last, true, true, extra)
|
||||
const token = generateToken(email, getWorkspaceId('', productId), getExtra(newAccount))
|
||||
const ws = await assignWorkspace(
|
||||
ctx,
|
||||
@ -2589,7 +2590,7 @@ export async function loginWithProvider (
|
||||
}
|
||||
return result
|
||||
}
|
||||
const newAccount = await createAcc(ctx, db, productId, branding, email, null, first, last, true, extra)
|
||||
const newAccount = await createAcc(ctx, db, productId, branding, email, null, first, last, true, true, extra)
|
||||
|
||||
const result = {
|
||||
endpoint: '',
|
||||
|
@ -55,6 +55,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@hcengineering/activity": "^0.6.0",
|
||||
"@hcengineering/analytics": "^0.6.0",
|
||||
"@hcengineering/analytics-service": "^0.6.0",
|
||||
"@hcengineering/chunter": "^0.6.20",
|
||||
"@hcengineering/client": "^0.6.18",
|
||||
"@hcengineering/client-resources": "^0.6.27",
|
||||
|
@ -26,6 +26,7 @@ export interface Config {
|
||||
OtpTimeToLiveSec: number
|
||||
OtpRetryDelaySec: number
|
||||
AccountsUrl: string
|
||||
SentryDSN: string
|
||||
}
|
||||
|
||||
const parseNumber = (str: string | undefined): number | undefined => (str !== undefined ? Number(str) : undefined)
|
||||
@ -39,12 +40,13 @@ const config: Config = (() => {
|
||||
AccountsUrl: process.env.ACCOUNTS_URL,
|
||||
ServiceId: process.env.SERVICE_ID,
|
||||
Secret: process.env.SECRET,
|
||||
Domain: process.env.DOMAIN,
|
||||
Domain: process.env.DOMAIN ?? '',
|
||||
BotPort: parseNumber(process.env.BOT_PORT) ?? 8443,
|
||||
// TODO: later we should get this title from branding map
|
||||
App: process.env.APP ?? 'Huly',
|
||||
OtpTimeToLiveSec: parseNumber(process.env.OTP_TIME_TO_LIVE_SEC) ?? 60,
|
||||
OtpRetryDelaySec: parseNumber(process.env.OTP_RETRY_DELAY_SEC) ?? 60
|
||||
OtpRetryDelaySec: parseNumber(process.env.OTP_RETRY_DELAY_SEC) ?? 60,
|
||||
SentryDSN: process.env.SENTRY_DSN ?? ''
|
||||
}
|
||||
|
||||
const missingEnv = (Object.keys(params) as Array<keyof Config>).filter((key) => params[key] === undefined)
|
||||
|
@ -86,6 +86,7 @@ const handleRequest = async (
|
||||
const token = extractToken(req.headers)
|
||||
await fn(req, res, token, next)
|
||||
} catch (err: unknown) {
|
||||
console.error('Error during extract token', err)
|
||||
next(err)
|
||||
}
|
||||
}
|
||||
@ -94,7 +95,7 @@ const wrapRequest = (fn: AsyncRequestHandler) => (req: Request, res: Response, n
|
||||
void handleRequest(fn, req, res, next)
|
||||
}
|
||||
|
||||
export function createServer (bot: Telegraf, worker: PlatformWorker): Express {
|
||||
export function createServer (bot: Telegraf, worker: PlatformWorker, ctx: MeasureContext): Express {
|
||||
const limiter = new Limiter()
|
||||
const app = express()
|
||||
|
||||
@ -174,28 +175,32 @@ export function createServer (bot: Telegraf, worker: PlatformWorker): Express {
|
||||
app.post(
|
||||
'/notify',
|
||||
wrapRequest(async (req, res, token) => {
|
||||
ctx.info('Received notification', { email: token.email })
|
||||
if (req.body == null || !Array.isArray(req.body)) {
|
||||
ctx.error('Invalid request body', { body: req.body, email: token.email })
|
||||
throw new ApiError(400)
|
||||
}
|
||||
const notificationRecords = req.body as TelegramNotificationRecord[]
|
||||
const usersRecords = await worker.getUsersRecords()
|
||||
const userRecord = await worker.getUserRecordByEmail(token.email)
|
||||
|
||||
if (userRecord === undefined) {
|
||||
ctx.error('User not found', { email: token.email })
|
||||
throw new ApiError(404)
|
||||
}
|
||||
|
||||
for (const notificationRecord of notificationRecords) {
|
||||
const userRecord = usersRecords.find((record) => record.email === token.email)
|
||||
if (userRecord !== undefined) {
|
||||
void limiter.add(userRecord.telegramId, async () => {
|
||||
const formattedMessage = toTelegramHtml(notificationRecord)
|
||||
const message = await bot.telegram.sendMessage(userRecord.telegramId, formattedMessage, {
|
||||
parse_mode: 'HTML'
|
||||
})
|
||||
await worker.addNotificationRecord({
|
||||
notificationId: notificationRecord.notificationId,
|
||||
email: userRecord.email,
|
||||
workspace: notificationRecord.workspace,
|
||||
telegramId: message.message_id
|
||||
})
|
||||
void limiter.add(userRecord.telegramId, async () => {
|
||||
const formattedMessage = toTelegramHtml(notificationRecord)
|
||||
const message = await bot.telegram.sendMessage(userRecord.telegramId, formattedMessage, {
|
||||
parse_mode: 'HTML'
|
||||
})
|
||||
}
|
||||
await worker.addNotificationRecord({
|
||||
notificationId: notificationRecord.notificationId,
|
||||
email: userRecord.email,
|
||||
workspace: notificationRecord.workspace,
|
||||
telegramId: message.message_id
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
res.status(200)
|
||||
|
@ -13,10 +13,13 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { MeasureMetricsContext } from '@hcengineering/core'
|
||||
import { MeasureMetricsContext, newMetrics } from '@hcengineering/core'
|
||||
import { setMetadata } from '@hcengineering/platform'
|
||||
import serverToken from '@hcengineering/server-token'
|
||||
import serverClient from '@hcengineering/server-client'
|
||||
import { SplitLogger, configureAnalytics } from '@hcengineering/analytics-service'
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import { join } from 'path'
|
||||
|
||||
import config from './config'
|
||||
import { createServer, listen } from './server'
|
||||
@ -24,17 +27,29 @@ import { setUpBot } from './bot'
|
||||
import { PlatformWorker } from './worker'
|
||||
import { registerLoaders } from './loaders'
|
||||
|
||||
const ctx = new MeasureMetricsContext(
|
||||
'telegram-bot-service',
|
||||
{},
|
||||
{},
|
||||
newMetrics(),
|
||||
new SplitLogger('telegram-bot-service', {
|
||||
root: join(process.cwd(), 'logs'),
|
||||
enableConsole: (process.env.ENABLE_CONSOLE ?? 'true') === 'true'
|
||||
})
|
||||
)
|
||||
|
||||
configureAnalytics(config.SentryDSN, config)
|
||||
Analytics.setTag('application', 'telegram-bot-service')
|
||||
|
||||
export const start = async (): Promise<void> => {
|
||||
setMetadata(serverToken.metadata.Secret, config.Secret)
|
||||
setMetadata(serverClient.metadata.Endpoint, config.AccountsUrl)
|
||||
setMetadata(serverClient.metadata.UserAgent, config.ServiceId)
|
||||
registerLoaders()
|
||||
|
||||
const ctx = new MeasureMetricsContext('telegram-bot', {})
|
||||
|
||||
const worker = await PlatformWorker.create()
|
||||
const bot = await setUpBot(worker)
|
||||
const app = createServer(bot, worker)
|
||||
const app = createServer(bot, worker, ctx)
|
||||
|
||||
if (config.Domain === '') {
|
||||
void bot.launch({ dropPendingUpdates: true })
|
||||
|
Loading…
Reference in New Issue
Block a user