diff --git a/.env b/.env index 502bda4..c18eee7 100644 --- a/.env +++ b/.env @@ -13,7 +13,7 @@ SMTP_MAIL_PASSWORD = b8953h9njd74zc5a # Rapidapi Translate Keys RAPID_API_KEY="56d811bd02mshe71a1ff794d4201p108f5ajsn8f745f6b4f1e" -RAPID_API_HOST="lingvanex-translate.p.rapidapi.com" +RAPID_API_HOST="text-translator2.p.rapidapi.com" # Expose/enable Swagger UI documentation ENABLE_SWAGGER='true' diff --git a/src/modules/auth/auth.controller.ts b/src/modules/auth/auth.controller.ts index 36a1ac3..a5638af 100644 --- a/src/modules/auth/auth.controller.ts +++ b/src/modules/auth/auth.controller.ts @@ -1,60 +1,60 @@ -import axios, { HttpStatusCode } from "axios"; -import { randomUUID } from "crypto"; -import { FastifyReply, FastifyRequest } from "fastify"; -import i18next from "i18next"; -import { FromSchema } from "json-schema-to-ts"; -import slugify from "slugify"; +import axios, { HttpStatusCode } from 'axios' +import { randomUUID } from 'crypto' +import { FastifyReply, FastifyRequest } from 'fastify' +import i18next from 'i18next' +import { FromSchema } from 'json-schema-to-ts' +import slugify from 'slugify' // import Resend, { GetEmailTemplate, render } from "@wordigo/email"; -import { Providers } from "@/utils/constants/enums"; -import messages from "@/utils/constants/messages"; -import { errorResult, successResult } from "@/utils/constants/results"; -import { pathsOfLanguages } from "@/utils/helpers/i18n.helper"; -import { createPasswordHash, verifyPasswordHash } from "@/utils/helpers/password.helper"; -import { createToken } from "@/utils/helpers/token.helper"; -import { GoogleAuthValidation, SignInValidation, SignUpValidation } from "./auth.schema"; -import { IGoogleUser } from "./auth.types"; +import { Providers } from '@/utils/constants/enums' +import messages from '@/utils/constants/messages' +import { errorResult, successResult } from '@/utils/constants/results' +import { pathsOfLanguages } from '@/utils/helpers/i18n.helper' +import { createPasswordHash, verifyPasswordHash } from '@/utils/helpers/password.helper' +import { createToken } from '@/utils/helpers/token.helper' +import { GoogleAuthValidation, SignInValidation, SignUpValidation } from './auth.schema' +import { IGoogleUser } from './auth.types' -type SignInValidationType = FromSchema; -type GoogleAuthValidationType = FromSchema; -type SignUpValidationType = FromSchema; +type SignInValidationType = FromSchema +type GoogleAuthValidationType = FromSchema +type SignUpValidationType = FromSchema export const SignUp = async (req: FastifyRequest<{ Body: SignUpValidationType }>, reply: FastifyReply) => { - const { email, password, name } = req.body; - const prisma = req.server.prisma; + const { email, password, name } = req.body + const prisma = req.server.prisma const isEmailExists = await req.server.prisma.users.findFirst({ where: { email, }, - }); - if (isEmailExists) return reply.send(errorResult(null, i18next.t(messages.user_already_exists))); + }) + if (isEmailExists) return reply.send(errorResult(null, i18next.t(messages.user_already_exists))) - const passwordHashAndSalt = await createPasswordHash(password); + const passwordHashAndSalt = await createPasswordHash(password) - let username; + let username while (true) { - const randomUID = randomUUID().split("-"); + const randomUID = randomUUID().split('-') username = slugify(`${name}-${randomUID[0]}${randomUID[1]}${randomUID[2]}`, { - replacement: "-", + replacement: '-', remove: undefined, // remove characters that match regex, defaults to `undefined` lower: true, strict: false, // strip special characters except replacement, defaults to `false` - locale: "vi", // language code of the locale to use + locale: 'vi', // language code of the locale to use trim: true, - }); + }) - const doesUserNameExist = await prisma.users.findFirst({ where: { username } }); + const doesUserNameExist = await prisma.users.findFirst({ where: { username } }) if (!doesUserNameExist) { - break; + break } } - let nativeLanguage = i18next.language; + let nativeLanguage = i18next.language if (!pathsOfLanguages.includes(nativeLanguage)) { - nativeLanguage = "en"; + nativeLanguage = 'en' } // const reactEmail = GetEmailTemplate({ type: "welcome", language: nativeLanguage as string, props: { name } }); @@ -72,56 +72,56 @@ export const SignUp = async (req: FastifyRequest<{ Body: SignUpValidationType }> nativeLanguage, provider: Providers.Local, }, - }); + }) - return reply.send(successResult(null, i18next.t(messages.success))); -}; + return reply.send(successResult(null, i18next.t(messages.success))) +} export const SignIn = async (req: FastifyRequest<{ Body: SignInValidationType }>, reply: FastifyReply) => { - const { email, username, password } = req.body; + const { email, username, password } = req.body - const user = await req.server.prisma.users.findFirst({ where: { OR: [{ email, username }] } }); + const user = await req.server.prisma.users.findFirst({ where: { OR: [{ email, username }] } }) if (!user) { - return reply.send(errorResult(null, i18next.t(messages.user_not_found))); + return reply.send(errorResult(null, i18next.t(messages.user_not_found))) } else if (user?.provider === Providers.Google) { - return reply.status(HttpStatusCode.Unauthorized).send(errorResult(null, i18next.t(messages.user_signed_dif_provider))); + return reply.status(HttpStatusCode.Unauthorized).send(errorResult(null, i18next.t(messages.user_signed_dif_provider))) } - const passwordVerification = await verifyPasswordHash(password, user?.passwordHash as string, user?.passwordSalt as string); + const passwordVerification = await verifyPasswordHash(password, user?.passwordHash as string, user?.passwordSalt as string) - if (!passwordVerification) return reply.status(HttpStatusCode.Unauthorized).send(errorResult(null, i18next.t(messages.user_wrong_password))); + if (!passwordVerification) return reply.status(HttpStatusCode.Unauthorized).send(errorResult(null, i18next.t(messages.user_wrong_password))) - const token = createToken(user.id); + const token = createToken(user.id) - return reply.send(successResult({ user, accessToken: token }, i18next.t(messages.success))); -}; + return reply.send(successResult({ user, accessToken: token }, i18next.t(messages.success))) +} export const GoogleOAuth = async (request: FastifyRequest<{ Querystring: GoogleAuthValidationType }>, reply: FastifyReply) => { - const { accessToken } = request.query; + const { accessToken } = request.query - const googleRequest = await axios.get("https://www.googleapis.com/oauth2/v3/userinfo", { + const googleRequest = await axios.get('https://www.googleapis.com/oauth2/v3/userinfo', { headers: { Authorization: `Bearer ${accessToken}`, }, - }); + }) - const googleUser = googleRequest.data as IGoogleUser; + const googleUser = googleRequest.data as IGoogleUser let user = await request.server.prisma.users.findFirst({ where: { email: googleUser.email as string, }, - }); + }) const username = slugify(`${googleUser.name}-${randomUUID()}`, { - replacement: "-", // replace spaces with replacement character, defaults to `-` + replacement: '-', // replace spaces with replacement character, defaults to `-` remove: undefined, // remove characters that match regex, defaults to `undefined` lower: true, // convert to lower case, defaults to `false` strict: false, // strip special characters except replacement, defaults to `false` - locale: "vi", // language code of the locale to use + locale: 'vi', // language code of the locale to use trim: true, // trim leading and trailing replacement chars, defaults to `true` - }); + }) if (!user) user = await request.server.prisma.users.create({ @@ -133,14 +133,14 @@ export const GoogleOAuth = async (request: FastifyRequest<{ Querystring: GoogleA nativeLanguage: googleUser.locale, provider: Providers.Google, }, - }); - else if (user.provider === Providers.Local) return reply.send(errorResult(null, i18next.t(messages.user_signed_dif_provider))); + }) + else if (user.provider === Providers.Local) return reply.send(errorResult(null, i18next.t(messages.user_signed_dif_provider))) // const token = sign({ email: user.email, id: user.id }, process.env["JWT_SECRET"] as string, { // expiresIn: "1h", // }); - const token = createToken(user.id); + const token = createToken(user.id) - return reply.send(successResult({ token, user }, i18next.t(messages.success))); -}; + return reply.send(successResult({ token, user }, i18next.t(messages.success))) +} diff --git a/src/modules/auth/auth.routes.ts b/src/modules/auth/auth.routes.ts index 7e09388..b8f6a0c 100644 --- a/src/modules/auth/auth.routes.ts +++ b/src/modules/auth/auth.routes.ts @@ -1,5 +1,5 @@ import { FastifyInstance } from 'fastify' -import { SignIn, GoogleOAuth, SignUp } from './auth.controller' +import { GoogleOAuth, SignIn, SignUp } from './auth.controller' import { GoogleAuthSchema, SignInSchema, SignUpSchema } from './auth.schema' export default async function (fastify: FastifyInstance) { diff --git a/src/modules/dictionaries/dictionaries.controller.ts b/src/modules/dictionaries/dictionaries.controller.ts index 1878f17..d69cc57 100644 --- a/src/modules/dictionaries/dictionaries.controller.ts +++ b/src/modules/dictionaries/dictionaries.controller.ts @@ -4,13 +4,13 @@ import slugify from 'slugify' import messages from '@/utils/constants/messages' import { errorResult, successResult } from '@/utils/constants/results' -import { AddWordValidation, CreateDictionaryValidation, GetDictionaryBySlugValidation, RemoveWordValidation, UpdateDictionaryValidation, UpdateImageValidation } from './dictionaries.schema' import { Words } from '@prisma/client' -import { DictionaryInitialTitle } from './dictionaries.types' -import { UploadingType, uploadImage } from '../../utils/helpers/fileUploading.helper' import { randomUUID } from 'crypto' import i18next from 'i18next' +import { UploadingType, uploadImage } from '../../utils/helpers/fileUploading.helper' import { checkingOfLanguages } from '../translation/translate.service' +import { AddWordValidation, CreateDictionaryValidation, GetDictionaryBySlugValidation, RemoveWordValidation, UpdateDictionaryValidation, UpdateImageValidation } from './dictionaries.schema' +import { DictionaryInitialTitle } from './dictionaries.types' type GetDictionaryBySlugType = FromSchema type CreateDictionaryType = FromSchema @@ -23,10 +23,12 @@ export const Create = async (req: FastifyRequest<{ Body: CreateDictionaryType }> const userId = req.user?.id const { title, targetLang, sourceLang } = req.body const prisma = req.server.prisma + console.log(messages.dictionary_already_exists) if (title && title.trim().toLowerCase() === DictionaryInitialTitle) return reply.send(errorResult(null, i18next.t(messages.dictionary_already_exists))) const doLangsExist = checkingOfLanguages(sourceLang as string, targetLang as string) + console.log(doLangsExist) if (!doLangsExist?.success) return reply.send(errorResult(null, i18next.t(doLangsExist?.message as string))) diff --git a/src/modules/translation/translate.controller.ts b/src/modules/translation/translate.controller.ts index 9eaf96f..52860cf 100644 --- a/src/modules/translation/translate.controller.ts +++ b/src/modules/translation/translate.controller.ts @@ -5,31 +5,37 @@ import { TranslationValidationBody } from './translate.schema' import messages from '@/utils/constants/messages' import { successResult } from '@/utils/constants/results' import i18next from 'i18next' - -import { options } from './translate.service' -import axios from 'axios' +import { translateApi } from './translate.service' type TranslationValidationTye = FromSchema export interface ITranslateOptions { - to?: string - from?: string - data?: string - platform: 'api' + target_language?: string + source_language?: string + text?: string } export async function TextTranslate(request: FastifyRequest<{ Body: TranslationValidationTye }>, reply: FastifyReply) { const { query, targetLanguage, sourceLanguage } = request.body const translateOptions: ITranslateOptions = { - data: query, - to: targetLanguage, - platform: 'api', + text: query, + target_language: targetLanguage, + source_language: 'auto', } - if (sourceLanguage !== 'detech') translateOptions.from = sourceLanguage - const { data } = await axios.create(options).post('https://lingvanex-translate.p.rapidapi.com/translate', translateOptions) + if (sourceLanguage !== 'auto') translateOptions.source_language = sourceLanguage + + const encodedParams = new URLSearchParams() + encodedParams.set('source_language', translateOptions.source_language as string) + encodedParams.set('target_language', translateOptions.target_language as string) + encodedParams.set('text', translateOptions.text as string) + + const { data: response } = await translateApi.post('https://text-translator2.p.rapidapi.com/translate', encodedParams).catch((err) => { + console.log(err) + return err + }) - const { translatedText, detectedSourceLanguage } = { translatedText: data.result, detectedSourceLanguage: data?.from } + const { translatedText, detectedSourceLanguage } = { translatedText: response.data?.translatedText, detectedSourceLanguage: response?.data?.detectedSourceLanguage?.code } return reply.send( successResult( diff --git a/src/modules/translation/translate.schema.ts b/src/modules/translation/translate.schema.ts index 41db2b5..ab0d834 100644 --- a/src/modules/translation/translate.schema.ts +++ b/src/modules/translation/translate.schema.ts @@ -6,7 +6,7 @@ export const TranslationValidationBody = { properties: { sourceLanguage: { type: 'string', - default:"detech" + default: 'auto', }, targetLanguage: { type: 'string', diff --git a/src/modules/translation/translate.service.ts b/src/modules/translation/translate.service.ts index 7c218e5..71aed29 100644 --- a/src/modules/translation/translate.service.ts +++ b/src/modules/translation/translate.service.ts @@ -1,15 +1,15 @@ import messages from '@/utils/constants/messages' +import { errorResult, successResult } from '@/utils/constants/results' +import axios from 'axios' import { AllCountryLanguages } from '../words/words.types' -import i18next from 'i18next' -import { errorResult } from '@/utils/constants/results' -export const options = { +export const translateApi = axios.create({ headers: { - 'content-type': 'application/json', + 'content-type': 'application/x-www-form-urlencoded', 'X-RapidAPI-Key': process.env.RAPID_API_KEY, 'X-RapidAPI-Host': process.env.RAPID_API_HOST, }, -} +}) export const checkingOfLanguages = (nativeLanguage: string, targetLanguage: string) => { const doLangsExist = AllCountryLanguages.filter((lang) => { @@ -19,4 +19,5 @@ export const checkingOfLanguages = (nativeLanguage: string, targetLanguage: stri if (doLangsExist.length !== 2) { return errorResult(null, messages.language_not_found) } + return successResult(null, messages.success) } diff --git a/src/modules/words/words.controller.ts b/src/modules/words/words.controller.ts index 941a4b5..7c8549a 100644 --- a/src/modules/words/words.controller.ts +++ b/src/modules/words/words.controller.ts @@ -1,15 +1,14 @@ +import { LearningStatuses } from '@/utils/constants/enums' import messages from '@/utils/constants/messages' import { errorResult, successResult } from '@/utils/constants/results' +import { randomUUID } from 'crypto' import { FastifyReply, FastifyRequest } from 'fastify' -import { FromSchema } from 'json-schema-to-ts' -import { CreateValidation, DeleteValidation } from './words.schema' -import { AllCountryLanguages } from './words.types' -import { DictionaryInitialTitle } from '../dictionaries/dictionaries.types' -import { LearningStatuses } from '@/utils/constants/enums' import i18next from 'i18next' -import { randomUUID } from 'crypto' +import { FromSchema } from 'json-schema-to-ts' import slugify from 'slugify' +import { DictionaryInitialTitle } from '../dictionaries/dictionaries.types' import { checkingOfLanguages } from '../translation/translate.service' +import { CreateValidation, DeleteValidation } from './words.schema' type CreateType = FromSchema type GetDictionaryByIdType = FromSchema