Skip to content

Commit 9a9eb6e

Browse files
committed
files upload done
1 parent e14c29d commit 9a9eb6e

File tree

11 files changed

+679
-20
lines changed

11 files changed

+679
-20
lines changed

app.js

+7-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import express from 'express';
22
import logger from 'morgan'; //пакет щоб логувати (виводити в консоль) запити - наприклад, для дебагінгу
33
import cors from 'cors';
44

5+
56
// імпорт маршрутів (окремі сторінки записної книги)
67
import authRouter from './routes/api/auth.js';
78
import contactsRouter from './routes/api/contacts.js';
@@ -11,11 +12,13 @@ const app = express(); // створили веб-сервер
1112
const formatsLogger = app.get('env') === 'development' ? 'dev' : 'short'
1213
// в режимі розробки виводиться повна інфо., а в режимі продакшина - коротка
1314

15+
// middlewares
16+
app.use(logger(formatsLogger));
17+
app.use(cors());
18+
app.use(express.json()); // перевіряє чи є тіло запиту (для post/put запитів), його тип (по заголовку Content-Type)...
19+
// якщо це application/json, то мідлвара буде рядком. JSON.parse перетворить формат тіла запиту на об'єкт
20+
app.use(express.static('public')); // якщо прийде запит на статичний файл, шукай його в папці public і віддавай
1421

15-
app.use(logger(formatsLogger)) // повертає middleware
16-
app.use(cors()) // повертає middleware
17-
app.use(express.json()) // перевіряє чи є тіло запиту (для post/put запитів), його тип (по заголовку Content-Type)...
18-
// якщо це application/json, то мідлвара буде рядком. JSON.parse перетворить формат тіла запиту на об'єкт
1922

2023
// якщо прийде запит, який починається з '/api/...', то обробник цього запиту шукай в authRouter/contactsRouter
2124
app.use('/api/auth', authRouter)

controllers/auth.js

+33-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import bcrypt from 'bcrypt'; // пакет для хешування (працює асинхронно)
22
import jwt from 'jsonwebtoken'; // пакет для створення токету
3+
import gravatar from 'gravatar';
4+
import fs from 'fs/promises';
5+
import path from 'path';
36
import { User } from '../models/user.js';
47
import { HttpError } from '../helpers/index.js';
58
import { ctrlWrapper } from '../decorators/index.js';
69

710
const { SECRET_KEY } = process.env; // беремо секретний ключ у змінних оточеннях
811

12+
913
const register = async(req, res) => {
1014
const { email, password } = req.body;
1115
const user = await User.findOne({email}); // чи є в БД користувач з таким email (знаходить перше співпадіння і повертає дані або null)
@@ -14,7 +18,9 @@ const register = async(req, res) => {
1418
}
1519
const hashPassword = await bcrypt.hash(password, 10); //перед тим як зберегти пароль в БД, хешуємо його
1620
// 10 - сіль - набір випадкових символів - складність алгоритму генерації солі
17-
const newUser = await User.create({...req.body, password: hashPassword}) // в БД зберігаємо пароль у захешованому вигляді (post-запит)
21+
22+
const avatarURL = gravatar.url(email); // генеруємо посилання на тимчасову аватарку
23+
const newUser = await User.create({ ...req.body, password: hashPassword, avatarURL }) // в БД зберігаємо пароль у захешованому вигляді (post-запит)
1824

1925
res.status(201).json({
2026
user: {
@@ -80,10 +86,36 @@ const updateSubscription = async(req, res) => {
8086
res.json(result); // статус 200 повертається автоматично
8187
};
8288

89+
90+
const avatarPath = path.resolve("public", "avatars"); // шлях до папки з файлом
91+
92+
const updateAvatar = async(req, res) => {
93+
const { _id } = req.user; // new ObjectId("64c6f0e733523b6f5a4ba4b8"),
94+
95+
const { path: oldPath, filename } = req.file; // path до temp; filename - нова назва файлу
96+
const newPath = path.join(avatarPath, filename); // створюємо новий шлях з ім'ям файлу
97+
await fs.rename(oldPath, newPath); // переміщення файла
98+
const avatarURL = path.join('avatars', filename); // записуємо шлях в body // папку 'public' не пишемо, вона вже вказана в мідлварі в app.js
99+
100+
await Contact.findByIdAndUpdate(_id, {avatarURL}); // знаючи id користувача, можемо перезаписати avatarURL
101+
// {
102+
// name: 'Zoi Doich',
103+
// email: '[email protected]',
104+
// phone: '(992) 914-3792',
105+
// favorite: false,
106+
// owner: new ObjectId("64c6f0e733523b6f5a4ba4b8"),
107+
// _id: new ObjectId("64c72713f9d52ec1573daf63"),
108+
// createdAt: 2023-07-31T03:14:27.161Z,
109+
// updatedAt: 2023-07-31T03:14:27.161Z
110+
// }
111+
res.status(201).json({avatarURL}); // успішно додали контакт на сервер
112+
}
113+
83114
export default { //огортаємо все в try/catch
84115
register: ctrlWrapper(register),
85116
login: ctrlWrapper(login),
86117
getCurrent: ctrlWrapper(getCurrent), //тут ми не викидаємо помилку, але для універсальності
87118
logout: ctrlWrapper(logout),
88119
updateSubscription: ctrlWrapper(updateSubscription),
120+
updateAvatar: ctrlWrapper(updateAvatar),
89121
}

controllers/contacts-controller.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import fs from 'fs/promises';
2+
import path from "path";
13
import { Contact } from '../models/contacts.js'; // імпорт моделі
24
import { HttpError } from '../helpers/index.js';
35
import { ctrlWrapper } from '../decorators/index.js';
46

57

6-
78
// --------------------------Запит на усі контакти користувача або тільки улюблені----------------------------------------------
89
const getAll = async (req, res) => {
910
const {_id: owner } = req.user; // дізнаємося, хто робить запит (деструктуризація з перейменуванням)
@@ -36,9 +37,17 @@ const getById = async (req, res) => {
3637

3738

3839
// -----------------------post-запит (додавання нового контакту)----------------------------------------------
40+
const avatarPath = path.resolve("public", "avatars"); // шлях до папки з файлом
41+
3942
const add = async (req, res) => {
4043
const { _id: owner } = req.user; // new ObjectId("64c6f0e733523b6f5a4ba4b8"),
41-
const result = await Contact.create({...req.body, owner}); // тепер кожний контакт буде належати конкретному його створювачу
44+
45+
// const { path: oldPath, filename } = req.file; // path до temp; filename - нова назва файлу
46+
// const newPath = path.join(avatarPath, filename); // створюємо новий шлях з ім'ям файлу
47+
// await fs.rename(oldPath, newPath); // переміщення файла
48+
// const avatar = path.join('avatars', filename); // папку 'public' не пишемо, вона вже вказана в мідлварі в app.js
49+
50+
const result = await Contact.create({...req.body, owner}); //avatar// тепер кожний контакт буде належати конкретному його створювачу
4251
// {
4352
// name: 'Zoi Doich',
4453
// email: '[email protected]',

middlewares/index.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// імпорт в routes/api/contacts.jsb
22
export { default as isEmptyBody } from './isEmptyBody.js';
33
export { default as isValidId } from './isValidId.js';
4-
export { default as authenticate } from './authenticate.js';
4+
export { default as authenticate } from './authenticate.js';
5+
export { default as upload } from './upload.js';

middlewares/upload.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import multer from 'multer'; // текстові поля перетворює на об'єкт і записує в req.body,
2+
// а файли зберігає в тимчас. папці (temp) і передає контролеру дані про цей файл (req.file)
3+
import path from 'path';
4+
5+
const destination = path.resolve('temp'); // шлях до папки з файлом
6+
7+
const storage = multer.diskStorage({
8+
destination,
9+
filename: (req, file, cb) => {
10+
const uniquePrefix = `${Date.now()}-${Math.round(Math.random() * 1E9)}`; // 1E9 = 1 billion = 1 * 10^9
11+
const filename = `${uniquePrefix}_${file.originalname}`; //створюємо унікальне і'мя файла
12+
cb(null, filename);
13+
}
14+
})
15+
16+
// Обмеження по розміру файла
17+
const limits = {
18+
fileSize: 1024 * 1024 * 5, // 1024 байтів = 1 Kb; 1024 * 1024 = 1 Mb; 1024 * 1024 * 5 = 5 Mb
19+
}
20+
21+
const upload = multer({
22+
storage,
23+
limits,
24+
});
25+
26+
export default upload;

models/contacts.js

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ const contactSchema = new Schema({
2828
type: Boolean,
2929
default: false,
3030
},
31+
avatarURL: String,
32+
// avatarURL: { те саме, що і вище
33+
// type: String,
34+
// },
3135
owner: { // той, хто надсилає запити
3236
type: Schema.Types.ObjectId, //тут зберігається id, який генерується mongoDB (особливий тип даних)
3337
ref: 'user', //назва колекції, з якої цей id

0 commit comments

Comments
 (0)