first structure
This commit is contained in:
@@ -3,7 +3,6 @@ SECRET=fDS9j269DSfd823FhdfG65
|
||||
ACCESS_TOKEN_SECERT=PNd98dsDS089ds3SDh7C5hg265SFC42bgHxTg34x
|
||||
ACCESS_TOKEN_SECERT_ADMIN=G89dsJsd90DFdsf96F8se3sgL7JB29265SFC42bgHxTg34x
|
||||
CONNECTION_STRING=
|
||||
CONNECTION_STRING_LOCAL=mongodb://127.0.0.1:27017/delearn?authSource=admin
|
||||
MERCHANT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
EMAIL_HOST=
|
||||
EMAIL_PORT=
|
||||
@@ -14,3 +13,6 @@ SMS_USER=
|
||||
SMS_PASS=
|
||||
SMS_NUMBER=
|
||||
URLIMAGE=https://api-delearn.iran.liara.run
|
||||
MONGO_CONNECTION_HOST=127.0.0.1 mongodb://127.0.0.1:27017/delearn
|
||||
MONGO_CONNECTION_PORT=27017
|
||||
MONGO_CONNECTION_NAME=delearn
|
||||
+61
-17
@@ -1,23 +1,67 @@
|
||||
module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
project: 'tsconfig.json',
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['@typescript-eslint/eslint-plugin'],
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
root: true,
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
jquery: true
|
||||
jest: true,
|
||||
},
|
||||
parserOptions: {
|
||||
parser: '@babel/eslint-parser',
|
||||
requireConfigFile: false
|
||||
},
|
||||
extends: ['@nuxtjs', 'plugin:nuxt/recommended', 'prettier'],
|
||||
plugins: [],
|
||||
// add your custom rules here
|
||||
rules: {
|
||||
'no-console': 'off',
|
||||
camelcase: 'off',
|
||||
'no-async-promise-executor': 'off',
|
||||
'vue/no-v-html': 'off',
|
||||
'vue/prop-name-casing': 'off'
|
||||
}
|
||||
}
|
||||
ignorePatterns: ['.eslintrc.js'],
|
||||
|
||||
rules: {
|
||||
'linebreak-style': 0,
|
||||
strict: 0,
|
||||
'max-len': ['error', { code: 120 }],
|
||||
'quote-props': 'off',
|
||||
'no-param-reassign': 'off',
|
||||
'no-underscore-dangle': 'off',
|
||||
'func-names': ['error', 'as-needed'],
|
||||
'prefer-const': 'warn',
|
||||
radix: 'off',
|
||||
'no-restricted-syntax': ['error', "BinaryExpression[operator='at']"],
|
||||
'no-await-in-loop': 'off',
|
||||
'no-trailing-spaces': 'off',
|
||||
'object-curly-spacing': 'off',
|
||||
'object-curly-newline': [
|
||||
'error',
|
||||
{
|
||||
ObjectExpression: {
|
||||
multiline: true,
|
||||
minProperties: 6,
|
||||
consistent: true,
|
||||
},
|
||||
ObjectPattern: { multiline: true, minProperties: 6, consistent: true },
|
||||
ImportDeclaration: {
|
||||
multiline: true,
|
||||
minProperties: 6,
|
||||
consistent: true,
|
||||
},
|
||||
ExportDeclaration: {
|
||||
multiline: true,
|
||||
minProperties: 6,
|
||||
consistent: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
'global-require': 'off',
|
||||
'import/no-dynamic-require': 'off',
|
||||
'@typescript-eslint/interface-name-prefix': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
endOfLine: 'auto',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
+39
-4
@@ -1,6 +1,41 @@
|
||||
# compiled output
|
||||
/dist
|
||||
/node_modules
|
||||
.png
|
||||
.jpg
|
||||
.web
|
||||
|
||||
*.png
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
pnpm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# package json
|
||||
package-lock.json
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
|
||||
# Tests
|
||||
/coverage
|
||||
/.nyc_output
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# Environments
|
||||
.env
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# Asanmarket
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
const mongoose = require("mongoose");
|
||||
const db = async () => {
|
||||
try {
|
||||
const connect = await mongoose.connect(process.env.CONNECTION_STRING);
|
||||
console.log(
|
||||
"Database connected: ",
|
||||
connect.connection.host,
|
||||
connect.connection.name
|
||||
);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
setTimeout(() => {
|
||||
console.log("Retry for DB");
|
||||
db();
|
||||
}, 5000);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = db;
|
||||
@@ -1,26 +0,0 @@
|
||||
const nodemailer = require("nodemailer");
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: process.env.EMAIL_HOST,
|
||||
port: process.env.EMAIL_PORT,
|
||||
secure: true,
|
||||
auth: {
|
||||
user: process.env.EMAIL_USER,
|
||||
pass: process.env.EMAIL_PASS,
|
||||
},
|
||||
});
|
||||
|
||||
const email = async (to, subject, text, html) => {
|
||||
|
||||
const info = await transporter.sendMail({
|
||||
from: `"Asan Market" ${process.env.EMAIL_ADDRESS}`, // sender address
|
||||
to: to, // list of receivers
|
||||
subject: subject, // Subject line
|
||||
text: text, // plain text body
|
||||
html: html, // html body
|
||||
});
|
||||
|
||||
|
||||
|
||||
};
|
||||
module.exports = email;
|
||||
@@ -1,57 +0,0 @@
|
||||
|
||||
const axios = require('axios')
|
||||
|
||||
const accountInfo = {
|
||||
Username: '000',
|
||||
Password: '000',
|
||||
Number: '000',
|
||||
url: 'http://www.afe.ir/WebService/V4/BoxService.asmx'
|
||||
}
|
||||
|
||||
/////// http post soap method
|
||||
module.exports.sms = (mobileNumbersArray, message) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
function renderMobileNumbers(array) {
|
||||
if (Array.isArray(array)) {
|
||||
return array.map(item => `<string>${item}</string>`).join('')
|
||||
} else {
|
||||
return `<string>${array}</string>`
|
||||
}
|
||||
}
|
||||
|
||||
const xml = `<?xml version="1.0" encoding="utf-8"?>
|
||||
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<soap:Body>
|
||||
<SendMessage xmlns="http://www.afe.ir/">
|
||||
<Username>${accountInfo.Username}</Username>
|
||||
<Password>${accountInfo.Password}</Password>
|
||||
<Number>${accountInfo.Number}</Number>
|
||||
<Mobile>
|
||||
${renderMobileNumbers(mobileNumbersArray)}
|
||||
</Mobile>
|
||||
<Message>${message}</Message>
|
||||
<Type>1</Type>
|
||||
</SendMessage>
|
||||
</soap:Body>
|
||||
</soap:Envelope>`
|
||||
|
||||
axios
|
||||
.post(accountInfo.url, xml, {
|
||||
headers: {
|
||||
'Content-Type': 'text/xml; charset=utf-8',
|
||||
SOAPAction: 'http://www.afe.ir/SendMessage'
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
resolve(res)
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(
|
||||
'this is sms module error ------------------ status code: %s error message: %s ',
|
||||
err.response.status,
|
||||
err.response.data
|
||||
)
|
||||
resolve(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
exports.constants = {
|
||||
VALIDATION_ERROR: 400,
|
||||
UNAUTHORIZED: 401,
|
||||
FORBIDOEN: 403,
|
||||
NOT_FOUND: 404,
|
||||
SERVER_ERROR: 500,
|
||||
SITE_UNAUTHORIZED: 422,
|
||||
TOO_MANY: 429,
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
const asyncHandler = require("express-async-handler");
|
||||
const News = require("../models/newsModels");
|
||||
const { email } = require("../config/emailConnection");
|
||||
const { checkValidations } = require("../plugins/HelperFunctions")
|
||||
const { body, validationResult } = require('express-validator')
|
||||
const { _sr } = require("../plugins/resServer")
|
||||
const { rateLimit } = require('express-rate-limit')
|
||||
|
||||
const limiter = rateLimit({
|
||||
windowMs: 24 * 60 * 60 * 1000, // 1 minutes
|
||||
limit: 1, // Limit each IP to 100 requests per `window` (here, per 15 minutes).
|
||||
standardHeaders: 'draft-7', // draft-6: `RateLimit-*` headers; draft-7: combined `RateLimit` header
|
||||
legacyHeaders: false, // Disable the `X-RateLimit-*` headers.
|
||||
message: { msg: "Too many requests, please try again later." }
|
||||
})
|
||||
|
||||
/**
|
||||
*@desc Add new email
|
||||
*@route POST /api/news/
|
||||
*@access private
|
||||
*/
|
||||
const addEmail = [
|
||||
[
|
||||
body('email').notEmpty().isEmail().withMessage(_sr.fa.required.email),
|
||||
],
|
||||
checkValidations(validationResult),
|
||||
limiter,
|
||||
asyncHandler(async (req, res) => {
|
||||
const { email } = req.body
|
||||
const alreadyEmail = await News.findOne({ email })
|
||||
if (alreadyEmail) {
|
||||
res.status(400);
|
||||
throw new Error(_sr.fa.duplicated.email);
|
||||
}
|
||||
const emailAdded = await News.create({
|
||||
email
|
||||
})
|
||||
res.status(200).json(emailAdded)
|
||||
})
|
||||
]
|
||||
|
||||
|
||||
module.exports = {
|
||||
baseRoute: "/news",
|
||||
items: [
|
||||
{
|
||||
off: false,
|
||||
route: "/",
|
||||
method: "post",
|
||||
middleware: [],
|
||||
use: addEmail
|
||||
},
|
||||
|
||||
]
|
||||
};
|
||||
@@ -1,60 +0,0 @@
|
||||
const asyncHandler = require("express-async-handler");
|
||||
const Site = require("../models/siteModels");
|
||||
const { _sr } = require("../plugins/resServer")
|
||||
|
||||
|
||||
/**
|
||||
*@desc Get all site
|
||||
*@route GET /api/sites/
|
||||
*@access Public
|
||||
*/
|
||||
const getSite = asyncHandler(async (req, res) => {
|
||||
const profile = await Site.findOne({ profile: "main" });
|
||||
res.status(200).json(profile);
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
*@desc Update a site
|
||||
*@route PUT /api/sites/
|
||||
*@access private
|
||||
*/
|
||||
const updateSite = [
|
||||
asyncHandler(async (req, res) => {
|
||||
const site = await Site.findOneAndUpdate(
|
||||
{ profile: "main" },
|
||||
req.body,
|
||||
{ new: true }
|
||||
);
|
||||
|
||||
if (!site) {
|
||||
res.status(404);
|
||||
throw new Error(_sr.fa.not_found.item_id);
|
||||
}
|
||||
res.status(200).json(site);
|
||||
})
|
||||
]
|
||||
|
||||
|
||||
|
||||
module.exports = {
|
||||
baseRoute: "/sites",
|
||||
items: [
|
||||
{
|
||||
off: false,
|
||||
route: "/",
|
||||
method: "get",
|
||||
middleware: ['validateAdminToken', 'hasPermission'],
|
||||
permission: "SITE",
|
||||
use: getSite
|
||||
},
|
||||
{
|
||||
off: false,
|
||||
route: "/id/:id",
|
||||
method: "put",
|
||||
middleware: ['validateAdminToken', 'hasPermission'],
|
||||
permission: "SITE",
|
||||
use: updateSite
|
||||
},
|
||||
]
|
||||
};
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"~/*": ["./*"],
|
||||
"@/*": ["./*"],
|
||||
"~~/*": ["./*"],
|
||||
"@@/*": ["./*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"app":"api-delearn",
|
||||
"port":"6060",
|
||||
"disks":[
|
||||
{
|
||||
"name": "uploads",
|
||||
"mountTo": "uploads"
|
||||
}
|
||||
],
|
||||
"node": {
|
||||
"version": "18"
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
const asyncHandler = require("express-async-handler");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const User = require("../models/userModels");
|
||||
|
||||
const validateToken = asyncHandler(async (req, res, next) => {
|
||||
let token = req.headers.authorization || req.headers.Authorization;
|
||||
|
||||
if (!token) {
|
||||
res.status(401);
|
||||
throw new Error("User is not authorized(N)");
|
||||
} else {
|
||||
const tokenA = await User.findOne({ token })
|
||||
if (tokenA) {
|
||||
jwt.verify(token, process.env.ACCESS_TOKEN_SECERT, (err, decoded) => {
|
||||
if (err) {
|
||||
res.status(401);
|
||||
throw new Error("User is not authorized(JWT E)");
|
||||
}
|
||||
req.user = decoded.user;
|
||||
next();
|
||||
});
|
||||
} else {
|
||||
res.status(401);
|
||||
throw new Error("User is not authorized(DB N)");
|
||||
}
|
||||
}
|
||||
});
|
||||
module.exports = { name: "validateToken", run: validateToken };
|
||||
@@ -1,62 +0,0 @@
|
||||
const { constants } = require("../constants");
|
||||
const errorHandler = (err, req, res, next) => {
|
||||
const statusCode = res.statusCode ? res.statusCode : 500;
|
||||
|
||||
switch (statusCode) {
|
||||
case constants.VALIDATION_ERROR:
|
||||
res.status(statusCode).json({
|
||||
title: "Validation Failed ",
|
||||
msg: err.message,
|
||||
stackTrace: err.stack,
|
||||
});
|
||||
break;
|
||||
case constants.NOT_FOUND:
|
||||
res.status(statusCode).json({
|
||||
title: "Not found ",
|
||||
msg: err.message,
|
||||
stackTrace: err.stack,
|
||||
});
|
||||
break;
|
||||
case constants.FORBIDOEN:
|
||||
res.status(statusCode).json({
|
||||
title: "Forbidoen ",
|
||||
msg: err.message,
|
||||
stackTrace: err.stack,
|
||||
});
|
||||
break;
|
||||
case constants.SERVER_ERROR:
|
||||
res.status(statusCode).json({
|
||||
title: "Server Error ",
|
||||
msg: err.message,
|
||||
stackTrace: err.stack,
|
||||
});
|
||||
break;
|
||||
case constants.UNAUTHORIZED:
|
||||
res.status(statusCode).json({
|
||||
title: "Unauthorized ",
|
||||
msg: err.message,
|
||||
stackTrace: err.stack,
|
||||
});
|
||||
break;
|
||||
case constants.SITE_UNAUTHORIZED:
|
||||
res.status(statusCode).json({
|
||||
title: "Site Unauthorized ",
|
||||
msg: err.message,
|
||||
stackTrace: err.stack,
|
||||
});
|
||||
break;
|
||||
case constants.TOO_MANY:
|
||||
res.status(statusCode).json({
|
||||
title: "Too many request",
|
||||
msg: err.message,
|
||||
stackTrace: err.stack,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.log(err);
|
||||
res.status(500).json({ err: err.message, msg: "Unhandled error" })
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = { name: "errorHandler", run: errorHandler };
|
||||
@@ -1,15 +0,0 @@
|
||||
const asyncHandler = require("express-async-handler");
|
||||
const User = require("../models/userModels");
|
||||
|
||||
const hasPerma = (perm) => {
|
||||
return asyncHandler(async (req, res, next) => {
|
||||
const user = await User.findId(req.user.id)
|
||||
if (user && (user.permissions.includes(perm) || !user.permissions.includes("ADMIN"))) {
|
||||
return next()
|
||||
} else {
|
||||
res.status(401); throw new Error('کاربر مجوز لازم را ندارد');
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = { name: "hasPermission", run: hasPerma };
|
||||
@@ -1,28 +0,0 @@
|
||||
const asyncHandler = require("express-async-handler");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const Admin = require("../models/adminModels");
|
||||
const validateAdminToken = asyncHandler(async (req, res, next) => {
|
||||
let token = req.headers.siteuser || req.headers.SiteUser;
|
||||
|
||||
if (!token) {
|
||||
res.status(401);
|
||||
throw new Error("User is not authorized(N)");
|
||||
} else {
|
||||
const tokenA = await Admin.findOne({ token })
|
||||
if (tokenA) {
|
||||
jwt.verify(token, process.env.ACCESS_TOKEN_SECERT_ADMIN, (err, decoded) => {
|
||||
if (err) {
|
||||
res.status(401);
|
||||
throw new Error("User is not authorized(JWT E)");
|
||||
}
|
||||
req.admin = decoded.user;
|
||||
next();
|
||||
});
|
||||
} else {
|
||||
res.status(401);
|
||||
throw new Error("User is not authorized(DB N)");
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
module.exports = { name: "validateAdminToken", run: validateAdminToken };
|
||||
@@ -1,28 +0,0 @@
|
||||
const asyncHandler = require("express-async-handler");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const User = require("../models/userModels");
|
||||
|
||||
const validateToken = asyncHandler(async (req, res, next) => {
|
||||
let token = req.headers.authorization || req.headers.Authorization;
|
||||
|
||||
if (!token) {
|
||||
res.status(401);
|
||||
throw new Error("User is not authorized(N)");
|
||||
} else {
|
||||
const tokenA = await User.findOne({ token })
|
||||
if (tokenA) {
|
||||
jwt.verify(token, process.env.ACCESS_TOKEN_SECERT, (err, decoded) => {
|
||||
if (err) {
|
||||
res.status(401);
|
||||
throw new Error("User is not authorized(JWT E)");
|
||||
}
|
||||
req.user = decoded.user;
|
||||
next();
|
||||
});
|
||||
} else {
|
||||
res.status(401);
|
||||
throw new Error("User is not authorized(DB N)");
|
||||
}
|
||||
}
|
||||
});
|
||||
module.exports = { name: "validateToken", run: validateToken };
|
||||
@@ -1,15 +0,0 @@
|
||||
const mongoose = require("mongoose");
|
||||
|
||||
const newsSchema = new mongoose.Schema({
|
||||
email: {
|
||||
type: String,
|
||||
unique: true
|
||||
}
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
versionKey: false
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = mongoose.model("News", newsSchema);
|
||||
@@ -1,59 +0,0 @@
|
||||
const mongoose = require("mongoose");
|
||||
|
||||
const siteSchema = new mongoose.Schema(
|
||||
{
|
||||
profile: {
|
||||
type: String,
|
||||
default: "main",
|
||||
unique: true
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: "Dlearn",
|
||||
},
|
||||
desc: {
|
||||
type: String,
|
||||
default: "Dlearn, marketplace core by Swift",
|
||||
},
|
||||
logo: {
|
||||
type: String,
|
||||
default: "/upload/Default.png",
|
||||
},
|
||||
tel1: {
|
||||
type: String,
|
||||
default: "+989391885657",
|
||||
},
|
||||
tel2: {
|
||||
type: String,
|
||||
default: "+989391885657",
|
||||
},
|
||||
address: {
|
||||
type: String,
|
||||
default: "Iran, Markazi",
|
||||
},
|
||||
socialMedia: [
|
||||
{
|
||||
kind: String,
|
||||
address: String
|
||||
}
|
||||
],
|
||||
emailHost: String,
|
||||
emailPort: String,
|
||||
emailUser: String,
|
||||
emailPass: String,
|
||||
smsNumber: String,
|
||||
smsUser: String,
|
||||
smsPass: String,
|
||||
underConstruction: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
versionKey: false
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = mongoose.model("Site", siteSchema);
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"collection": "@nestjs/schematics",
|
||||
"sourceRoot": "src"
|
||||
}
|
||||
Generated
-4648
File diff suppressed because it is too large
Load Diff
+109
-26
@@ -1,34 +1,117 @@
|
||||
{
|
||||
"name": "asanmarket",
|
||||
"name": "DLearn",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"private": true,
|
||||
"license": "UNLICENSED",
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"dev": "nodemon server.js"
|
||||
"prebuild": "rimraf dist",
|
||||
"build": "nest build",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||
"start": "nest start",
|
||||
"start:dev": "nest start --watch",
|
||||
"start:debug": "nest start --debug --watch",
|
||||
"start:prod": "node dist/main",
|
||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:cov": "jest --coverage",
|
||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||
},
|
||||
"author": "swift",
|
||||
"license": "MIT",
|
||||
"author": "daniel.3380",
|
||||
"dependencies": {
|
||||
"axios": "^1.6.2",
|
||||
"bcrypt": "^5.1.0",
|
||||
"cors": "^2.8.5",
|
||||
"cron": "^3.1.6",
|
||||
"dotenv": "^16.3.1",
|
||||
"express": "^4.18.2",
|
||||
"express-async-handler": "^1.2.0",
|
||||
"express-fileupload": "^1.4.1",
|
||||
"express-rate-limit": "^7.2.0",
|
||||
"express-route-detector": "^1.1.0",
|
||||
"express-sharp": "^4.2.41",
|
||||
"express-validator": "^7.0.1",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"moment": "^2.29.4",
|
||||
"mongodb": "^5.6.0",
|
||||
"mongoose": "^7.3.1",
|
||||
"mongoose-sequence": "^6.0.1",
|
||||
"nodemailer": "^6.9.4",
|
||||
"nodemon": "^2.0.22",
|
||||
"swiftly-tools": "1.2.82"
|
||||
"@nestjs/axios": "^2.0.0",
|
||||
"@nestjs/common": "^10.0.5",
|
||||
"@nestjs/core": "^10.0.5",
|
||||
"@nestjs/mongoose": "^10.0.6",
|
||||
"@nestjs/platform-express": "^10.0.5",
|
||||
"@nestjs/platform-socket.io": "^10.0.5",
|
||||
"@nestjs/serve-static": "^4.0.0",
|
||||
"@nestjs/swagger": "^7.1.1",
|
||||
"@nestjs/testing": "^9.4.0",
|
||||
"@nestjs/throttler": "^4.0.0",
|
||||
"@types/axios": "^0.14.0",
|
||||
"@types/crypto-js": "^4.1.1",
|
||||
"@types/express-session": "1.17.0",
|
||||
"@types/moment": "^2.13.0",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/request": "^2.48.8",
|
||||
"@types/request-ip": "^0.0.37",
|
||||
"axios": "^1.3.6",
|
||||
"base64-async": "^2.1.3",
|
||||
"bluebird": "^3.7.2",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.0",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"crypto-js": "^4.1.1",
|
||||
"dotenv": "^16.4.5",
|
||||
"ejs": "^3.1.8",
|
||||
"express-session": "^1.17.2",
|
||||
"fs": "^0.0.1-security",
|
||||
"jalali-moment": "^3.3.11",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"md5": "^2.3.0",
|
||||
"mongoose": "^8.3.2",
|
||||
"mysql": "^2.18.1",
|
||||
"mysql2": "^3.2.3",
|
||||
"path": "^0.12.7",
|
||||
"pg": "^8.11.1",
|
||||
"pm2": "^5.2.0",
|
||||
"qrcode": "^1.5.0",
|
||||
"random-number": "^0.0.9",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"request": "^2.88.2",
|
||||
"request-ip": "^2.1.3",
|
||||
"rimraf": "^3.0.2",
|
||||
"rxjs": "^7.5.5",
|
||||
"sequelize": "^6.32.1",
|
||||
"sequelize-typescript": "^2.1.5",
|
||||
"shelljs": "^0.8.5",
|
||||
"soap": "^1.0.0",
|
||||
"swagger-ui-express": "^4.6.3",
|
||||
"ts-loader": "^9.4.2",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^8.2.5",
|
||||
"@nestjs/schematics": "^8.0.11",
|
||||
"@types/bluebird": "^3.5.36",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/jest": "27.0.2",
|
||||
"@types/jsonwebtoken": "^8.5.8",
|
||||
"@types/md5": "^2.3.2",
|
||||
"@types/node": "^16.11.33",
|
||||
"@types/qrcode": "^1.4.2",
|
||||
"@types/supertest": "^2.0.12",
|
||||
"@typescript-eslint/eslint-plugin": "^5.22.0",
|
||||
"@typescript-eslint/parser": "^5.22.0",
|
||||
"eslint": "^8.15.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest": "^27.5.1",
|
||||
"prettier": "^2.6.2",
|
||||
"source-map-support": "^0.5.20",
|
||||
"supertest": "^6.2.3",
|
||||
"ts-jest": "^27.1.4",
|
||||
"ts-node": "^10.7.0",
|
||||
"tsconfig-paths": "^3.14.1"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"json",
|
||||
"ts"
|
||||
],
|
||||
"rootDir": "src",
|
||||
"testRegex": ".*\\.spec\\.ts$",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
},
|
||||
"collectCoverageFrom": [
|
||||
"**/*.(t|j)s"
|
||||
],
|
||||
"coverageDirectory": "../coverage",
|
||||
"testEnvironment": "node"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
module.exports = {
|
||||
populate: {
|
||||
|
||||
},
|
||||
select: {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const moment = require("moment");
|
||||
const date = moment();
|
||||
|
||||
const uploadImage = (image, res, type) => {
|
||||
const maxSize = 15 * 1024 * 1024; // 15MB (example limit)
|
||||
|
||||
if (image.size > maxSize) {
|
||||
res.status(500)
|
||||
throw new Error("Image file size exceeds the limit")
|
||||
}
|
||||
let imageName =
|
||||
date.format("YYYY-MM-DD") +
|
||||
"-Img-" +
|
||||
Math.floor(Math.random() * 900) +
|
||||
100 +
|
||||
image.name;
|
||||
|
||||
let saveToPath
|
||||
let preFile
|
||||
|
||||
switch (type) {
|
||||
case "1":
|
||||
// Specify the save location
|
||||
saveToPath = path.join(__dirname, "..", "uploads/products", imageName);
|
||||
preFile = "/uploads/products/"
|
||||
break;
|
||||
|
||||
case "2":
|
||||
// Specify the save location
|
||||
saveToPath = path.join(__dirname, "..", "uploads/blogs", imageName);
|
||||
preFile = "/uploads/blogs/"
|
||||
break;
|
||||
|
||||
case "3":
|
||||
// Specify the save location
|
||||
saveToPath = path.join(__dirname, "..", "uploads/personal", imageName);
|
||||
preFile = "/uploads/personal/"
|
||||
break;
|
||||
|
||||
default:
|
||||
// Specify the save location
|
||||
saveToPath = path.join(__dirname, "..", "uploads/none", imageName);
|
||||
preFile = "/uploads/none/"
|
||||
break;
|
||||
}
|
||||
|
||||
fs.writeFile(saveToPath, image.data, (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ msg: "Error saving the image" });
|
||||
} else {
|
||||
res.status(201).json({ url: `${preFile}${imageName}` });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const uploadImages = (images, res, type) => {
|
||||
const maxSize = 15 * 1024 * 1024; // 15MB (example limit)
|
||||
const imageUrls = [];
|
||||
|
||||
if (!Array.isArray(images)) {
|
||||
|
||||
if (images.size > maxSize) {
|
||||
res.status(500)
|
||||
throw new Error("Image file size exceeds the limit")
|
||||
}
|
||||
|
||||
let imageName =
|
||||
date.format("YYYY-MM-DD") +
|
||||
"-Img-" +
|
||||
Math.floor(Math.random() * 900) +
|
||||
100 +
|
||||
images.name;
|
||||
|
||||
let saveToPath
|
||||
let preFile
|
||||
|
||||
switch (type) {
|
||||
case "1":
|
||||
// Specify the save location
|
||||
saveToPath = path.join(__dirname, "..", "uploads/products", imageName);
|
||||
preFile = "/uploads/products/"
|
||||
break;
|
||||
|
||||
case "2":
|
||||
// Specify the save location
|
||||
saveToPath = path.join(__dirname, "..", "uploads/blogs", imageName);
|
||||
preFile = "/uploads/blogs/"
|
||||
break;
|
||||
|
||||
case "3":
|
||||
// Specify the save location
|
||||
saveToPath = path.join(__dirname, "..", "uploads/personal", imageName);
|
||||
preFile = "/uploads/personal/"
|
||||
break;
|
||||
|
||||
default:
|
||||
// Specify the save location
|
||||
saveToPath = path.join(__dirname, "..", "uploads/none", imageName);
|
||||
preFile = "/uploads/none/"
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
fs.writeFile(saveToPath, images.data, (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ msg: "Error saving the image" });
|
||||
} else {
|
||||
imageUrls.push(`${preFile}${imageName}`)
|
||||
res.status(201).json({ urls: imageUrls });
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
images.forEach(async (image) => {
|
||||
if (image.size > maxSize) {
|
||||
res.status(400)
|
||||
throw new Error("Image file size exceeds the limit")
|
||||
}
|
||||
|
||||
let imageName =
|
||||
date.format("YYYY-MM-DD") +
|
||||
"-Img-" +
|
||||
Math.floor(Math.random() * 900) +
|
||||
100 +
|
||||
image.name;
|
||||
|
||||
let saveToPath
|
||||
let preFile
|
||||
|
||||
|
||||
switch (type) {
|
||||
case "1":
|
||||
// Specify the save location
|
||||
saveToPath = path.join(__dirname, "..", "uploads/products", imageName);
|
||||
preFile = "/uploads/products/"
|
||||
break;
|
||||
|
||||
case "2":
|
||||
// Specify the save location
|
||||
saveToPath = path.join(__dirname, "..", "uploads/blogs", imageName);
|
||||
preFile = "/uploads/blogs/"
|
||||
break;
|
||||
|
||||
case "3":
|
||||
// Specify the save location
|
||||
saveToPath = path.join(__dirname, "..", "uploads/personal", imageName);
|
||||
preFile = "/uploads/personal/"
|
||||
break;
|
||||
|
||||
default:
|
||||
// Specify the save location
|
||||
saveToPath = path.join(__dirname, "..", "uploads/none", imageName);
|
||||
preFile = "/uploads/none/"
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
imageUrls.push(`${preFile}${imageName}`);
|
||||
|
||||
fs.writeFile(saveToPath, image.data, (err) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
res.status(500)
|
||||
throw new Error("Can't save images")
|
||||
okd = false
|
||||
}
|
||||
});
|
||||
});
|
||||
res.status(201).json({ urls: imageUrls });
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const deleteImage = (address, res) => {
|
||||
const addressOf = path.join(__dirname, "..", address);
|
||||
|
||||
fs.unlink(addressOf, (err) => {
|
||||
if (err) {
|
||||
console.error("Error removing image:", err);
|
||||
return;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
deleteImage,
|
||||
uploadImage,
|
||||
uploadImages,
|
||||
};
|
||||
@@ -1,314 +0,0 @@
|
||||
module.exports._sr = {
|
||||
fa: {
|
||||
required: {
|
||||
token: 'توکن را وارد کنید',
|
||||
field: 'این فیلد نباید خالی باشد',
|
||||
// developer validations
|
||||
remember_me: 'پارامتر remember_me الزامی است',
|
||||
// registration validations
|
||||
name: 'نام را وارد کنید',
|
||||
first_name: 'نام را وارد کنید',
|
||||
last_name: 'نام خانوادگی را وارد کنید',
|
||||
email: 'ایمیل را وارد کنید',
|
||||
national_code: 'کد ملی الزامی است',
|
||||
email_personal: 'ایمیل شخصی الزامی است',
|
||||
email_company: 'ایمیل کمپانی برای اشخاص حقوقی الزامی است',
|
||||
company_name: 'درصورتی که شخص حقوقی هستید، نام کمپانی را وارد کنید',
|
||||
username: 'نام کاربری را وارد کنید',
|
||||
phone_number: 'شماره تماس را وارد کنید',
|
||||
gender: "جنسیت خود را انتخاب کنید",
|
||||
password: 'پسورد را وارد کنید',
|
||||
birthdate: 'تاریخ تولد را وارد کنید',
|
||||
permissions: 'مقدار دسترسی را وارد کنید',
|
||||
// addressing validations
|
||||
country: 'کشور را وارد کنید',
|
||||
province: 'استان را وارد کنید',
|
||||
city: 'شهر را وارد کنید',
|
||||
address: 'آدرس را وارد کنید',
|
||||
postal_code: 'کد پستی را وارد کنید',
|
||||
plaque: 'پلاک را وارد کنید',
|
||||
receiver_first_name: 'نام گیرنده را وارد کنید',
|
||||
receiver_last_name: 'نام خانوادگی گیرنده را وارد کنید',
|
||||
receiver_mobile: 'شماره موبایل گیرنده را وارد کنید',
|
||||
// global (post - gallery - ...)
|
||||
title: 'عنوان را وارد کنید',
|
||||
caption: 'متن را وارد کنید',
|
||||
description: 'توضیحات را وارد کنید',
|
||||
category: 'دسته بندی را انتخاب کنید',
|
||||
image: 'عکس اجباری است',
|
||||
cover: 'کاور اجباری است',
|
||||
file: 'فایل اجباری است',
|
||||
message: 'پیام را بنویسید',
|
||||
quantity: 'تعداد را وارد کنید',
|
||||
date: 'تاریخ را وارد کنید',
|
||||
reason: 'دلیل را انتخاب کنید',
|
||||
question: 'سوال را بنویسید',
|
||||
answer: 'جواب را بنویسید',
|
||||
price: 'قیمت را وارد کنید',
|
||||
type: 'نوع را انتخاب کنید',
|
||||
discount_code: 'کد تخفیف را وارد کنید',
|
||||
discount_amount: 'مقدار تخفیف را وارد کنید',
|
||||
discount_expire_date: 'تاریخ انقضای کد تخفیف را مشخص کنید',
|
||||
user_id: 'کاربر را انتخاب کنید',
|
||||
video: 'ویدیو اجباری است',
|
||||
setting_name: 'نام تنظیمات اجباری است',
|
||||
setting_value: 'مقدار تنظیمات اجباری است'
|
||||
},
|
||||
format: {
|
||||
phone_number: 'فرمت شماره تماس صحیح نیست',
|
||||
email: 'فرمت ایمیل قابل قبول نیست',
|
||||
number: 'مقدار باید از جنس عدد باشد',
|
||||
boolean: 'مقدار باید از جنس Boolean باشد',
|
||||
image: 'فرمت عکس قابل قبول نیست',
|
||||
video: 'فرمت ویدیو قابل قبول نیست',
|
||||
national_code: 'کد ملی صحیح نیست'
|
||||
},
|
||||
min_char: {
|
||||
min2: 'حداقل 2 کاراکتر',
|
||||
min4: 'حداقل 4 کاراکتر',
|
||||
min8: 'حداقل 8 کاراکتر',
|
||||
min10: 'حداقل 10 کاراکتر',
|
||||
min20: 'حداقل 20 کاراکتر',
|
||||
min30: 'حداقل 30 کاراکتر',
|
||||
min40: 'حداقل 40 کاراکتر',
|
||||
min50: 'حداقل 50 کاراکتر',
|
||||
min60: 'حداقل 60 کاراکتر',
|
||||
min100: 'حداقل 100 کاراکتر',
|
||||
min120: 'حداقل 120 کاراکتر',
|
||||
min150: 'حداقل 150 کاراکتر',
|
||||
min200: 'حداقل 200 کاراکتر',
|
||||
data_size: 'حجم قابل قبول حداقل: ',
|
||||
image_width_size: 'عرض حداقل: ',
|
||||
image_height_size: 'ارتفاع حداقل: '
|
||||
},
|
||||
max_char: {
|
||||
max4: 'حداکثر 4 کاراکتر',
|
||||
max8: 'حداکثر 8 کاراکتر',
|
||||
max10: 'حداکثر 10 کاراکتر',
|
||||
max15: 'حداکثر 15 کاراکتر',
|
||||
max20: 'حداکثر 20 کاراکتر',
|
||||
max30: 'حداکثر 30 کاراکتر',
|
||||
max40: 'حداکثر 40 کاراکتر',
|
||||
max50: 'حداکثر 50 کاراکتر',
|
||||
max60: 'حداکثر 60 کاراکتر',
|
||||
max100: 'حداکثر 100 کاراکتر',
|
||||
max120: 'حداکثر 120 کاراکتر',
|
||||
max150: 'حداکثر 150 کاراکتر',
|
||||
max200: 'حداکثر 200 کاراکتر',
|
||||
data_size: 'حجم قابل قبول حداکثر: ',
|
||||
image_width_size: 'عرض حداکثر: ',
|
||||
image_height_size: 'ارتفاع حداکثر: '
|
||||
},
|
||||
not_found: {
|
||||
user_id: 'کاربری با این مشخصات وجود ندارد',
|
||||
admin_id: 'ادمینی با این مشخصات وجود ندارد',
|
||||
order_id: 'سفارشی با این مشخصات وجود ندارد',
|
||||
item_id: 'موردی با این مشخصات وجود ندارد',
|
||||
password: 'رمز عبور یا آیدی درست نیست',
|
||||
user_not_exist: 'اطلاعات یوزر موجود نیست'
|
||||
},
|
||||
duplicated: {
|
||||
username: 'این نام کاربری از قبل وجود دارد',
|
||||
email: 'این ایمیل از قبل وجود دارد',
|
||||
name: 'نام تکراری است',
|
||||
title: 'عنوان تکراری است',
|
||||
phone_number: 'این شماره تماس از قبل وجود دارد',
|
||||
link: 'این لینک تکراری است',
|
||||
code: ' این کد تکراری است',
|
||||
item: 'این مورد تگراری است',
|
||||
shop: 'این فروشگاه وجود دارد'
|
||||
},
|
||||
response: {
|
||||
permissions: 'شما مجوز کافی ندارید ',
|
||||
logged_in: 'شما وارد سیستم شدید',
|
||||
not_logged_in: 'شما وارد سیستم نشدید',
|
||||
logged_out: 'شما از سیستم خارج شدید',
|
||||
unauthenticated: 'غیرمجاز',
|
||||
recovery_link: 'لینک بازیابی فرستاده شد',
|
||||
success_save: 'با موفقیت ثبت شد',
|
||||
success_remove: 'با موفقیت حذف شد',
|
||||
cart_empty: 'سبد خرید خالی است',
|
||||
already_has_address: 'آدرس قبلا اضافه شده',
|
||||
activation_code: 'کد فعالسازی برای شما ارسال شد',
|
||||
activation_email: 'ایمیل فعال سازی برای شما ارسال شد',
|
||||
expired_reset_link: 'این لینک بازیابی منقضی شده است',
|
||||
email_not_confirmed: 'ابتدا ایمیل خود را تایید کنید،لینک فعال سازی قبلا برای شما فرستاده شده است.',
|
||||
expired_activation_link: 'این لینک فعال سازی منقضی شده است',
|
||||
success_activation: 'اکانت شما با موفقیت فعال شد',
|
||||
passwords_not_match: 'پسورد ها یکی نیست',
|
||||
problem: 'مشکلی پیش آمده، لطفا دوباره تلاش کنید.',
|
||||
latinChar: 'لطفا با حروف لاتین بنویسید',
|
||||
persianChar: 'لطفا با حروف فارسی بنویسید',
|
||||
whiteSpace: 'بین حروف و کلمات نباید فاصله باشد',
|
||||
wrongLoginEmail: 'ایمیل یا رمز ورود اشتباه است',
|
||||
wrongLoginNumber: 'شماره یا رمز ورود اشتباه است',
|
||||
user_not_valid: 'اطلاعات یوزر معتبر نیست',
|
||||
otp: 'کد اشتباه است'
|
||||
},
|
||||
file_types: {
|
||||
jpg: 'فقط فرمت jpg قابل قبول است',
|
||||
png: 'فقط فرمت png قابل قبول است',
|
||||
gif: 'فقط فرمت gif قابل قبول است',
|
||||
pdf: 'فقط فرمت pdf قابل قبول است',
|
||||
txt: 'فقط فرمت txt قابل قبول است',
|
||||
log: 'فقط فرمت log قابل قبول است',
|
||||
mp3: 'فقط فرمت mp3 قابل قبول است',
|
||||
ogg: 'فقط فرمت ogg قابل قبول است',
|
||||
wmv: 'فقط فرمت wmv قابل قبول است',
|
||||
mp4: 'فقط فرمت mp4 قابل قبول است',
|
||||
mov: 'فقط فرمت mov قابل قبول است',
|
||||
mkv: 'فقط فرمت mkv قابل قبول است',
|
||||
flv: 'فقط فرمت flv قابل قبول است'
|
||||
}
|
||||
},
|
||||
en: {
|
||||
required: {
|
||||
token: 'Token is required',
|
||||
field: 'This field is required',
|
||||
// developer validations
|
||||
remember_me: 'Remember_me parameter required',
|
||||
// registration validations
|
||||
name: 'Enter name',
|
||||
first_name: 'Enter first name',
|
||||
last_name: 'Enter last name',
|
||||
national_code: 'National code is required',
|
||||
email: 'Enter email',
|
||||
email_personal: 'Personal email is required',
|
||||
email_company: 'Company email is required for legal entities',
|
||||
company_name: 'Enter company name if you are a legal entity',
|
||||
username: 'Enter username',
|
||||
phone_number: 'Enter phone number',
|
||||
password: 'Enter password',
|
||||
birthdate: 'Enter birthdate',
|
||||
// addressing validations
|
||||
country: 'Enter country',
|
||||
province: 'Enter province',
|
||||
city: 'Enter city',
|
||||
address: 'Enter address',
|
||||
postal_code: 'Enter postal code',
|
||||
plaque: 'Enter plaque',
|
||||
receiver_first_name: 'Enter recipient name',
|
||||
receiver_last_name: 'Enter recipient surname',
|
||||
receiver_mobile: "Enter recipient's mobile number",
|
||||
// global (post - gallery - ...)
|
||||
title: 'Enter title',
|
||||
caption: 'Enter caption',
|
||||
description: 'Enter description',
|
||||
category: 'Select category',
|
||||
image: 'Image is required',
|
||||
cover: 'Cover is required',
|
||||
file: 'File is required',
|
||||
message: 'Write message',
|
||||
quantity: 'Enter quantity',
|
||||
date: 'Enter date',
|
||||
reason: 'Select reason',
|
||||
question: 'Write the question',
|
||||
answer: 'Write the answer',
|
||||
price: 'Enter Price',
|
||||
type: 'Select type',
|
||||
discount_code: 'Enter discount code',
|
||||
discount_amount: 'Enter discount amount',
|
||||
discount_expire_date: 'Specify discount code expiration date',
|
||||
user_id: 'Select user',
|
||||
video: 'Video is required'
|
||||
},
|
||||
format: {
|
||||
phone_number: 'Phone number format in incorrect',
|
||||
email: 'Email format is not correct',
|
||||
number: 'Value must be number',
|
||||
boolean: 'Value must be Boolean',
|
||||
image: 'Photo format is not acceptable',
|
||||
video: 'Video format is not acceptable',
|
||||
national_code: 'National code format is not correct'
|
||||
},
|
||||
min_char: {
|
||||
min2: 'At least 2 characters',
|
||||
min4: 'At least 4 characters',
|
||||
min8: 'At least 8 characters',
|
||||
min10: 'At least 10 characters',
|
||||
min20: 'At least 20 characters',
|
||||
min30: 'At least 30 characters',
|
||||
min40: 'At least 40 characters',
|
||||
min50: 'At least 50 characters',
|
||||
min60: 'At least 60 characters',
|
||||
min100: 'At least 100 characters',
|
||||
min120: 'At least 120 characters',
|
||||
min150: 'At least 150 characters',
|
||||
min200: 'At least 200 characters',
|
||||
data_size: 'Acceptable minimum size: ',
|
||||
image_width_size: 'Minimum width: ',
|
||||
image_height_size: 'Minimum height: '
|
||||
},
|
||||
max_char: {
|
||||
max4: 'Maximum 4 characters',
|
||||
max8: 'Maximum 8 characters',
|
||||
max10: 'Maximum 10 characters',
|
||||
max15: 'Maximum 15 characters',
|
||||
max20: 'Maximum 20 characters',
|
||||
max30: 'Maximum 30 characters',
|
||||
max40: 'Maximum 40 characters',
|
||||
max50: 'Maximum 50 characters',
|
||||
max60: 'Maximum 60 characters',
|
||||
max100: 'Maximum 100 characters',
|
||||
max120: 'Maximum 120 characters',
|
||||
max150: 'Maximum 150 characters',
|
||||
max200: 'Maximum 200 characters',
|
||||
data_size: 'Maximum acceptable size: ',
|
||||
image_width_size: 'Maximum width: ',
|
||||
image_height_size: 'Maximum height: '
|
||||
},
|
||||
not_found: {
|
||||
user_id: 'There is no user with this profile',
|
||||
admin_id: 'There is no admin with this profile',
|
||||
order_id: 'There is no order with this profile',
|
||||
item_id: 'There is no item with this specification',
|
||||
password: 'Password or ID is incorrect'
|
||||
},
|
||||
duplicated: {
|
||||
username: 'This username already exists',
|
||||
email: 'This email already exists',
|
||||
name: 'Name already exists',
|
||||
title: 'Title already exists',
|
||||
phone_number: 'Phone number already exists'
|
||||
},
|
||||
response: {
|
||||
logged_in: 'You are logged in',
|
||||
not_logged_in: 'You are not logged in',
|
||||
logged_out: 'You are logged out',
|
||||
unauthenticated: 'unauthenticated',
|
||||
recovery_link: 'Recovery link sent',
|
||||
success_save: 'Successfully saved',
|
||||
success_remove: 'Successfully removed',
|
||||
cart_empty: 'Cart is empty',
|
||||
already_has_address: 'Already has address',
|
||||
activation_code: 'Activation code sent to you',
|
||||
activation_email: 'Activation email sent to you',
|
||||
expired_reset_link: 'The current reset pass link has been expired',
|
||||
email_not_confirmed: 'Confirm your email first, the activation link has already been sent to you.',
|
||||
expired_activation_link: 'This activation link has expired',
|
||||
success_activation: 'Your account has been successfully activated',
|
||||
passwords_not_match: 'Passwords are not the same',
|
||||
problem: 'There is a problem, please try again.',
|
||||
latinChar: 'Please write in Latin letters',
|
||||
persianChar: 'Please write in Persian letters',
|
||||
whiteSpace: 'There should be no space between letters and words'
|
||||
},
|
||||
file_types: {
|
||||
jpg: 'Only jpg format is acceptable',
|
||||
png: 'Only png format is acceptable',
|
||||
gif: 'Only gif format is acceptable',
|
||||
pdf: 'Only pdf format is acceptable',
|
||||
txt: 'Only txt format is acceptable',
|
||||
log: 'Only log format is acceptable',
|
||||
mp3: 'Only mp3 format is acceptable',
|
||||
ogg: 'Only ogg format is acceptable',
|
||||
wmv: 'Only wmv format is acceptable',
|
||||
mp4: 'Only mp4 format is acceptable',
|
||||
mov: 'Only mov format is acceptable',
|
||||
mkv: 'Only mkv format is acceptable',
|
||||
flv: 'Only flv format is acceptable'
|
||||
}
|
||||
},
|
||||
supportedImageFormats: ['jpg', 'jpeg', 'png', 'svg', 'svg+xml', 'webp'],
|
||||
supportedVideoFormats: ['mp4', 'wmv']
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
const express = require("express");
|
||||
const errorHandler = require("./middleware/errorHandler");
|
||||
const videovalidate = require("./middleware/vidoeValidate");
|
||||
const db = require("./config/dbConnectoin");
|
||||
const fileUpload = require("express-fileupload");
|
||||
const path = require("path");
|
||||
const swiftly = require("swiftly-tools");
|
||||
const { expressSharp, FsAdapter } = require('express-sharp')
|
||||
const { autoFetch } = require('express-route-detector')
|
||||
var cors = require('cors')
|
||||
require("dotenv").config();
|
||||
|
||||
// Init database
|
||||
db();
|
||||
|
||||
const app = express();
|
||||
const port = process.env.PORT || 6060;
|
||||
|
||||
// Middleware
|
||||
app.use(cors())
|
||||
app.use(fileUpload());
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: false }));
|
||||
app.use(swiftly.middleware.hsts)
|
||||
app.use(swiftly.middleware.sign("Mr Swift"))
|
||||
|
||||
// Routes
|
||||
app.use(autoFetch(express))
|
||||
app.use(autoFetch(express, pAddress = "hasPermission", cAddress = "Admin", mAddress = "middleware"))
|
||||
|
||||
app.use('/uploads', expressSharp({
|
||||
imageAdapter: new FsAdapter(path.join(__dirname, 'uploads')),
|
||||
}));
|
||||
app.use('/vid', videovalidate.run, expressSharp({
|
||||
imageAdapter: new FsAdapter(path.join(__dirname, 'Videos')),
|
||||
}));
|
||||
|
||||
//Error handler
|
||||
app.use(errorHandler.run);
|
||||
|
||||
//Init site data
|
||||
Site.findOne({ profile: "main" }).then(async (data) => {
|
||||
if (!data) {
|
||||
await Site.create({
|
||||
profile: "main",
|
||||
});
|
||||
}
|
||||
}).catch(async (err) => {
|
||||
await Site.create({
|
||||
profile: "main",
|
||||
});
|
||||
})
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server runing on port: ${port}`);
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ThrottlerModule } from '@nestjs/throttler';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
// ServeStaticModule.forRoot({
|
||||
// rootPat h: join(__dirname, '..', 'public'),
|
||||
// }),
|
||||
// ConfigModule.forRoot({
|
||||
// isGlobal: true,
|
||||
// }),
|
||||
ThrottlerModule.forRoot({
|
||||
ttl: 60,
|
||||
limit: 10,
|
||||
}),
|
||||
],
|
||||
controllers: [],
|
||||
providers: [],
|
||||
})
|
||||
export class AppModule {}
|
||||
@@ -0,0 +1 @@
|
||||
{ "mongoDb": "mongodb://127.0.0.1:27017/admin" }
|
||||
@@ -0,0 +1,16 @@
|
||||
import * as path from 'path';
|
||||
|
||||
const pathes = {
|
||||
staticFiles: './../public',
|
||||
viewFiles: './views',
|
||||
userQrCodeFiles: '../public/user/qrCodes',
|
||||
uploadedFiles: '/files/',
|
||||
tinymceUpload: '/tinymceUpload/',
|
||||
// siteUrl: 'http://172.16.27.32/api',
|
||||
// clientUrl: 'http://172.16.27.32/api',
|
||||
siteUrl: 'http://localhost:4123',
|
||||
clientUrl: 'http://localhost:4123',
|
||||
appRoot: path.resolve(),
|
||||
};
|
||||
|
||||
export default pathes;
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"title": "DLearn ",
|
||||
"description": "DLearn APIs",
|
||||
"version": "1.0.0",
|
||||
"tag": "DLearn Apis"
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import * as session from 'express-session';
|
||||
import { AppModule } from './app.module';
|
||||
import mongoose from 'mongoose';
|
||||
import * as dotenv from 'dotenv';
|
||||
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
||||
import * as swaggerConfig from './config/swagger.json';
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
import { NestExpressApplication } from '@nestjs/platform-express';
|
||||
import paths from './config/paths';
|
||||
dotenv.config();
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create<NestExpressApplication>(AppModule, {
|
||||
cors: true,
|
||||
});
|
||||
const db =
|
||||
// app.setGlobalPrefix('api/v1');
|
||||
// app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)));
|
||||
app.useGlobalPipes(new ValidationPipe());
|
||||
app.use(
|
||||
session({
|
||||
name: 'DLearn',
|
||||
secret: '68yzNk6SQuPFY#WREFDF^&%TERGH765rtgfHJ%$ERFDF@#$!dg^5r%aALM1',
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
}),
|
||||
);
|
||||
app.useStaticAssets(paths.staticFiles);
|
||||
app.setBaseViewsDir(paths.viewFiles);
|
||||
app.setViewEngine('ejs');
|
||||
app.use((req, res, next) => {
|
||||
res.header('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('X-Powered-By', 'NestJs');
|
||||
res.setHeader(
|
||||
'Access-Control-Allow-Methods',
|
||||
'GET, POST, OPTIONS, PUT, PATCH, DELETE',
|
||||
);
|
||||
res.setHeader(
|
||||
'Access-Control-Allow-Headers',
|
||||
'X-Requested-With,content-type',
|
||||
);
|
||||
res.setHeader('Access-Control-Allow-Credentials', true);
|
||||
res.header(
|
||||
'Access-Control-Allow-Headers',
|
||||
'Origin, X-Requested-With, Content-Type, Accept',
|
||||
);
|
||||
next();
|
||||
});
|
||||
mongoose.connect(
|
||||
// eslint-disable-next-line max-len
|
||||
`mongodb://${process.env.MONGO_CONNECTION_HOST}:${process.env.MONGO_CONNECTION_PORT}/${process.env.MONGO_CONNECTION_NAME}`,
|
||||
);
|
||||
const config = new DocumentBuilder()
|
||||
.setTitle(swaggerConfig.title)
|
||||
.setDescription(swaggerConfig.description)
|
||||
.setVersion(swaggerConfig.version)
|
||||
.addTag(swaggerConfig.tag)
|
||||
.build();
|
||||
const document = SwaggerModule.createDocument(app, config);
|
||||
SwaggerModule.setup('api/v1', app, document);
|
||||
await app.listen(3000);
|
||||
}
|
||||
bootstrap();
|
||||
@@ -0,0 +1,44 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
|
||||
/**
|
||||
* A mongoose schema plugin which applies the following in the toJSON transform call:
|
||||
* - removes __v, createdAt, updatedAt, and any path that has private: true
|
||||
* - replaces _id with id
|
||||
*/
|
||||
|
||||
const deleteAtPath = (obj, path, index) => {
|
||||
if (index === path.length - 1) {
|
||||
delete obj[path[index]];
|
||||
return;
|
||||
}
|
||||
deleteAtPath(obj[path[index]], path, index + 1);
|
||||
};
|
||||
|
||||
const cleanJson = (schema) => {
|
||||
let transform;
|
||||
if (schema.options.toJSON && schema.options.toJSON.transform) {
|
||||
transform = schema.options.toJSON.transform;
|
||||
}
|
||||
|
||||
schema.options.toJSON = Object.assign(schema.options.toJSON || {}, {
|
||||
transform(doc, ret, options) {
|
||||
Object.keys(schema.paths).forEach((path) => {
|
||||
if (schema.paths[path].options && schema.paths[path].options.private) {
|
||||
deleteAtPath(ret, path.split('.'), 0);
|
||||
}
|
||||
});
|
||||
|
||||
ret.id = ret._id.toString();
|
||||
delete ret._id;
|
||||
delete ret.isDeleted;
|
||||
delete ret.deletedAt;
|
||||
delete ret.__v;
|
||||
delete ret.updatedAt;
|
||||
if (transform) {
|
||||
return transform(doc, ret, options);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export default cleanJson;
|
||||
@@ -0,0 +1,2 @@
|
||||
import cleanJson from './cleanJson.plugin';
|
||||
export { cleanJson };
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "es2017",
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"incremental": true,
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": false,
|
||||
"noImplicitAny": false,
|
||||
"strictBindCallApply": false,
|
||||
"forceConsistentCasingInFileNames": false,
|
||||
"noFallthroughCasesInSwitch": false,
|
||||
"resolveJsonModule": true
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# Asanmarket
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Asanmarket
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
# Asanmarket
|
||||
Reference in New Issue
Block a user