upd
This commit is contained in:
+3
-1
@@ -1 +1,3 @@
|
||||
PORT=3000
|
||||
PORT=3000
|
||||
MONGO_URI=mongodb://root:p62Z!ZatgY25@194.26.138.94:27017/
|
||||
JWT_SECRET=yDcdWJgvlj2bJAuovYfQHTvtc3U9xQPw
|
||||
+7
-1
@@ -11,12 +11,18 @@
|
||||
"dependencies": {
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.3.1",
|
||||
"express": "^4.18.2"
|
||||
"express": "^4.18.2",
|
||||
"mongoose": "^8.0.1",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"sharp": "^0.32.6",
|
||||
"uuid": "^9.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.15",
|
||||
"@types/express": "^4.17.20",
|
||||
"@types/multer": "^1.4.11",
|
||||
"@types/node": "^20.8.10",
|
||||
"@types/uuid": "^9.0.7",
|
||||
"nodemon": "^3.0.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { connect } from "mongoose";
|
||||
|
||||
async function connectDB() {
|
||||
try {
|
||||
await connect(process.env.MONGO_URI!, { dbName: "estate" });
|
||||
console.log("MongoDB connected...");
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
console.error(error.message);
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
export default connectDB;
|
||||
@@ -1,62 +0,0 @@
|
||||
const db = {
|
||||
products: [
|
||||
{
|
||||
id: 1,
|
||||
name: "Смартфон POCO C51 64 ГБ",
|
||||
price: 6499,
|
||||
image:
|
||||
"https://c.dns-shop.ru/thumb/st1/fit/500/500/256e8ece17c46e683dbe0facd94c5e69/5c108f7da6e5886d4d32d723d0e24ad0151bd790d7941374c56d9d8e9718d9f6.jpg.webp",
|
||||
colors: ["black", "blue", "green"],
|
||||
popularity: 3,
|
||||
desc: `Смартфон POCO C51 64 ГБ предлагает функции, необходимые для разговоров по мобильной связи, общения в социальных сетях и мультимедийных развлечений. Он выполнен в компактном пластиковом корпусе с обтекаемыми гранями и тыловой панелью голубого цвета. Экран IPS диагональю 6.52 дюйма обеспечивает интуитивное управление и реалистичное изображение.
|
||||
Высокая производительность системы достигается благодаря 8-ядерному процессору MediaTek Helio G36 и 2 ГБ оперативной памяти. На тыловой панели установлена сдвоенная камера 8+0.3 Мп с автофокусом и светодиодной вспышкой для реалистичной съемки фотографий и видео. Фронтальная камера 5 Мп позволяет делать селфи и общаться по видеосвязи. Встроенный сканер отпечатков пальцев гарантирует простую и безопасную разблокировку устройства. За автономность смартфона POCO C51 отвечает аккумуляторная батарея емкостью 5000 мА*ч.`,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Смартфон realme C30s 64 ГБ",
|
||||
price: 6999,
|
||||
image:
|
||||
"https://c.dns-shop.ru/thumb/st1/fit/500/500/774bc3d792cbcab34769a178c61686f2/cb157601cb15ceac4756053ed94ff8a9b2598f461f86084ca57090724cd9214e.jpg.webp",
|
||||
colors: ["black", "blue"],
|
||||
popularity: 3,
|
||||
desc: `Смартфон realme C30S имеет тонкий корпус черного цвета и вес 186 г, что облегчает эксплуатацию. Для разграничения звонков можно установить две SIM-карты. Модель оснащена мощным производительным 8-ядерным процессором, который обеспечивает бесперебойную и быструю работу. Широкий экран диагональю 6.5 дюймов обеспечивает комфортную игру и просмотр фильмов. IPS-дисплей поддерживает насыщенную и яркую цветопередачу.
|
||||
Смартфон realme C30S имеет 64 ГБ памяти, чего достаточно для хранения необходимой информации. Батарея емкостью 5000 мА*ч позволяет долгое время играть или смотреть видео без подзарядки. Даже при остатке 5% можно включить режим энергосбережения, чтобы оставаться на связи. Для быстрой разблокировки экрана на боковой стороне корпуса есть сканер отпечатка пальцев.`,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Смартфон Xiaomi Redmi A2+ 64 ГБ",
|
||||
price: 7499,
|
||||
image:
|
||||
"https://c.dns-shop.ru/thumb/st1/fit/500/500/43aa8e3640bdc253df179db3eecd9cd3/b5926e67b994494fd67cdf8b75d9db0bad7bc5f4bc9839937ffc3daf7053abdc.jpg.webp",
|
||||
colors: ["black", "blue", "green"],
|
||||
popularity: 5,
|
||||
desc: `Смартфон Xiaomi Redmi A2+ в голубом цвете корпуса поддерживает установку двух SIM-карт, чтобы вы могли разграничить личные и деловые звонки. Экран обладает диагональю 6.52” и разрешением 1600x720 для комфортного просмотра любого контента. Закаленное стекло способствует защите дисплея от мелких повреждений: потертостей и царапин. 8-ядерный процессор MediaTek Helio G36 вместе с 3 ГБ оперативной памяти обеспечивает достаточный уровень производительности для запуска мобильных приложений и работы в режиме многозадачности.
|
||||
Смартфон Xiaomi Redmi A2+ имеет 64 ГБ встроенной памяти и предусматривает отдельный слот, в который можно установить карту памяти емкостью до 1 ТБ. Тыловая камера представлена двумя модулями 8+0.3 Мп для съемки детализированных и красочных снимков. Двойная светодиодная вспышка позволит проводить фотосъемку в условиях плохой освещенности. Для создания селфи предусмотрена 5-мегапиксельная фронтальная камера. Литий-полимерный аккумулятор емкостью 5000 мАч позволит устройству проработать в режиме разговора до 28 ч.`,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Смартфон Infinix SMART 7 HD 64 ГБ",
|
||||
price: 6999,
|
||||
image:
|
||||
"https://c.dns-shop.ru/thumb/st1/fit/500/500/746f2653ecd116f0b3f5bc3e1ce6040f/8a0c3b832d57c5ea8faae411b3afd708403516a91e448da83efb13ef5d6696bd.jpg.webp",
|
||||
colors: ["white", "black", "blue"],
|
||||
popularity: 2,
|
||||
desc: `Смартфон Infinix Smart 7 HD 64 ГБ выполнен в корпусе белого цвета и оснащен дисплеем 6.6 дюйма. Панель IPS (1612x720 пикселей) воспроизводит реалистичное изображение с насыщенными и яркими цветами. Плавная и бесперебойная работа аппаратной платформы при выполнении различных задач обеспечивается благодаря процессору Unisoc SC9863A и 2 ГБ оперативной памяти.
|
||||
Infinix Smart 7 HD оснащен слотами для установки двух карт SIM и карты памяти microSD. Основная камера 8+0.3 Мп предназначена для создания детализированных фотографий и видео. На передней стороне в каплевидном вырезе расположена камера 5 Мп, которая позволяет общаться по видеосвязи и делать селфи. В устройстве реализованы беспроводные интерфейсы Wi-Fi и Bluetooth. Аккумулятор 5000 мА*ч гарантирует до 32 часов работы смартфона без подзарядки в режиме просмотра видео.`,
|
||||
},
|
||||
|
||||
{
|
||||
id: 5,
|
||||
name: "Смартфон Tecno POP 7 64 ГБ",
|
||||
price: 8499,
|
||||
image:
|
||||
"https://c.dns-shop.ru/thumb/st4/fit/500/500/8278fc2e0c767175a1bc3fe505284ca7/88c242ac48d30b2977c1802c8ad41f63484c9e2bb3a0976befc7d0bb7caa6c6e.jpg.webp",
|
||||
colors: ["black", "blue", "purple"],
|
||||
popularity: 4,
|
||||
desc: `Смартфон Tecno POP 7 в пластиковом корпусе голубого цвета обладает многоуровневой биометрической защитой. Она запускает идентификацию личности по отпечатку и чертам лица. Процессор с 8 ядрами и 2 ГБ оперативной памяти выступают гарантом быстрого запуска приложений и отклика на пожелания пользователя. Энергия аккумулятора емкостью 5000 мАч рассчитана на длительное использование функционала.
|
||||
Смартфон Tecno POP 7 оснащен основной камерой с разрешением матрицы 8 Мп и светодиодной вспышкой. Кадры получатся насыщенными даже в условиях слабого освещения. В 6.6-дюймовый экран интегрирован датчик, который анализирует уровень внешнего освещения. Он автоматически уменьшает или повышает яркость для комфортного просмотра контента.`,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default db;
|
||||
+7
-3
@@ -1,6 +1,11 @@
|
||||
import "dotenv/config";
|
||||
import connectDB from "./config/db";
|
||||
import express, { json } from "express";
|
||||
import cors from "cors";
|
||||
import uploadRouter from "./routes/upload";
|
||||
import projectsRouter from "./routes/projects";
|
||||
|
||||
await connectDB();
|
||||
|
||||
const app = express();
|
||||
const port = process.env.PORT || 3000;
|
||||
@@ -8,9 +13,8 @@ const port = process.env.PORT || 3000;
|
||||
app.use(json());
|
||||
app.use(cors());
|
||||
|
||||
app.get("/", (_req, res) => {
|
||||
res.json({ ok: 1 });
|
||||
});
|
||||
app.use("/upload", uploadRouter);
|
||||
app.use("/projects", projectsRouter);
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server is listening on port ${port}`);
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { Schema, model } from "mongoose";
|
||||
|
||||
const projectSchema = new Schema(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
company: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
city: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
image: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
stage: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
releaseYear: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
devices: {
|
||||
type: Array,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
toJSON: { virtuals: true },
|
||||
toObject: { virtuals: true },
|
||||
}
|
||||
);
|
||||
|
||||
const Project = model("Project", projectSchema);
|
||||
|
||||
export default Project;
|
||||
@@ -0,0 +1,76 @@
|
||||
import { Router } from "express";
|
||||
import Project from "../models/Project";
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get("/", async (_req, res) => {
|
||||
try {
|
||||
const projects = await Project.find().sort({ createdAt: -1 });
|
||||
|
||||
return res.json(projects);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
return res.json({ error: error.message });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/:id", async (req, res) => {
|
||||
try {
|
||||
const project = await Project.findById(req.params.id);
|
||||
|
||||
return res.json(project);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
return res.json({ error: error.message });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/", async (req, res) => {
|
||||
try {
|
||||
const project = await Project.create(req.body);
|
||||
|
||||
return res.json(project);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
return res.json({ error: error.message });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
router.put("/:id", async (req, res) => {
|
||||
console.log(req.body);
|
||||
|
||||
try {
|
||||
const project = await Project.findByIdAndUpdate(req.params.id, req.body, {
|
||||
upsert: true,
|
||||
new: true,
|
||||
});
|
||||
|
||||
console.log("updated", project);
|
||||
|
||||
return res.json(project);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
return res.json({ error: error.message });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
router.delete("/:id", async (req, res) => {
|
||||
console.log(req.body);
|
||||
|
||||
try {
|
||||
const project = await Project.findByIdAndDelete(req.params.id);
|
||||
|
||||
return res.json(project);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
return res.json({ error: error.message });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const projectsRouter = router;
|
||||
export default projectsRouter;
|
||||
@@ -0,0 +1,61 @@
|
||||
import { Router } from "express";
|
||||
import multer, { memoryStorage } from "multer";
|
||||
import sharp from "sharp";
|
||||
import fs from "fs";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
const router = Router();
|
||||
|
||||
const upload = multer({
|
||||
dest: "uploads/",
|
||||
storage: memoryStorage(),
|
||||
fileFilter: (_req, file, cb) => {
|
||||
if (file.mimetype.split("/")[0] === "image") {
|
||||
cb(null, true);
|
||||
} else {
|
||||
cb(new Error("Only images are allowed!"));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
router.get("/:file", (req, res) => {
|
||||
const fileName = req.params.file;
|
||||
|
||||
try {
|
||||
const readStream = fs.createReadStream(`uploads/${fileName}`);
|
||||
readStream.pipe(res);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
return res.json({ error: error.message });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/", upload.single("file"), async (req, res) => {
|
||||
if (!req.file) {
|
||||
return res.json({ error: "req.file" });
|
||||
}
|
||||
|
||||
try {
|
||||
const filename = `${uuidv4()}.jpg`;
|
||||
|
||||
await sharp(req.file.buffer)
|
||||
.resize({
|
||||
width: 512,
|
||||
height: 512,
|
||||
fit: "inside",
|
||||
withoutEnlargement: true,
|
||||
})
|
||||
.jpeg({ quality: 90 })
|
||||
.toFile(`uploads/${filename}`);
|
||||
|
||||
return res.json({ file: `http://192.168.1.170:3000/upload/${filename}` });
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
return res.json({ error: error.message });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const uploadRouter = router;
|
||||
export default uploadRouter;
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
+1473
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user