Skip to content

Commit

Permalink
v2.0.0
Browse files Browse the repository at this point in the history
v2.0.0
  • Loading branch information
TheKostVK authored Mar 24, 2023
2 parents e89daf8 + bc3d7d3 commit efd04ed
Show file tree
Hide file tree
Showing 66 changed files with 1,912 additions and 23,128 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/node_modules/
/media/uploads/posts/preview
.idea
/media/uploads/
80 changes: 77 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,77 @@
<p>Проект React</p>
<p>ide: WebStorm -v 2022.3.2</p>
<p>Выполненые задание находятся в ветке Releases</p>
<div align="center">
<p>Проект ReactJS Backend</p>
<p>ide: WebStorm -v 2022.3</p>
<p>Выполненные задания находятся в ветке <span style="color: cyan">Releases</span></p>
<p>Выполнили: <a href="https://github.com/TheKostVK">TheKostVK</a> и <a href="https://github.com/b1abb">b1abb</a></p>
</div>


<p align="center">Ссылки на проекты GitHub</p>
<table align="center">
<tr>
<th align="center"><a href="https://github.com/TheKostVK/react2023_frontend">Frontend</a></th>
<th align="center"><a href="https://github.com/TheKostVK/react2023_backend">Backend</a></th>
</tr>
</table>

<p align="center">Таблица используемых модулей</p>
<table align="center">
<tr>
<th style="color: blueviolet; font-size: large">Frontend</th>
<th style="color: blueviolet; font-size: large">Backend</th>
</tr>
<tr>
<td><p style="color: brown">ReactJS v18</p></td>
<td><p style="color: brown">NodeJS/ES6</p></td>
</tr>
<tr>
<td>
<p style="font-size: large; color: black">Redux Toolkit</p>
<p style="color: brown">(глобальный стейт менеджер)</p>
</td>
<td>
<p style="font-size: large; color: black">Express + Validator</p>
<p style="color: brown">(веб-сервер/валидация запросов)</p>
</td>
</tr>
<tr>
<td>
<p style="font-size: large; color: black">React Hook Form</p>
<p style="color: brown">(работа с формами)</p>
</td>
<td>
<p style="font-size: large; color: black">MongoDB/Mongoose</p>
<p style="color: brown">(работа с базой данных)</p>
</td>
</tr>
<tr>
<td>
<p style="font-size: large; color: black">Redux Router v6</p>
<p style="color: brown">(навигация/роутинг)</p>
</td>
<td>
<p style="font-size: large; color: black">JSON Web Token</p>
<p style="color: brown">(аутентификация/авторизация)</p>
</td>
</tr>
<tr>
<td>
<p style="font-size: large; color: black">React Markdown/Simple Editor</p>
<p style="color: brown">(редактор статей)</p>
</td>
<td>
<p style="font-size: large; color: black">Multer</p>
<p style="color: brown">(загрузка файлов/изображений)</p>
</td>
</tr>
<tr>
<td>
<p style="font-size: large; color: black">Axios</p>
<p style="color: brown">(отправка запросов на сервер)</p>
</td>
<td>
<p style="font-size: large; color: black">BCrypt</p>
<p style="color: brown">(шифрование пароля)</p>
</td>
</tr>
</table>
135 changes: 135 additions & 0 deletions controllers/PostController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import PostModel from '../models/Post.js';

export const getLastTags = async (req, res) => {
try {

const posts = await PostModel.find().limit(5).exec();

const tags = posts.map(obj => obj.tags).flat().slice(0, 5);

res.json(tags);
} catch (err) {
console.log(err)
res.status(500).json({
message: 'Не удалось получить теги',
});
}
};

export const getAll = async (req, res) => {
try {
const posts = await PostModel.find().populate('user').exec();

res.json(posts);
} catch (err) {
console.log(err)
res.status(500).json({
message: 'Не удалось получить статьи',
});
}
};

export const getOne = async (req, res) => {
try {
const postId = req.params.id;

const post = await PostModel.findOneAndUpdate(
{
_id: postId,
},
{
$inc: {viewsCount: 1},
},
{
returnDocument: 'after',
}
).populate('user').exec();

if (!post) {
return res.status(404).json({
message: 'Статья не найдена',
});
}

res.json(post);
} catch (err) {
console.log(err)
res.status(500).json({
message: 'Не удалось получить статью',
});
}
};


export const create = async (req, res) => {
try {
const doc = new PostModel({
title: req.body.title,
text: req.body.text,
imageUrl: req.body.imageUrl,
tags: req.body.tags,
user: req.userId,
});

const post = await doc.save();

res.json(post);
} catch (err) {
console.log(err)
res.status(500).json({
message: 'Не удалось создать статью',
});
}
};

export const remove = async (req, res) => {
try {
const postId = req.params.id;

const post = await PostModel.findOneAndDelete(
{
_id: postId,
});

if (!post) {
return res.status(404).json({
message: 'Статья не найдена',
});
}

res.json({
success: true,
});
} catch (err) {
console.log(err)
res.status(500).json({
message: 'Не удалось удалить статью',
});
}
};

export const update = async (req, res) => {
try {
const postId = req.params.id;

await PostModel.updateOne({
_id: postId,
},
{
title: req.body.title,
text: req.body.text,
imageUrl: req.body.imageUrl,
user: req.userId,
tags: req.body.tags,
},
);
res.json({
success: true,
});
} catch (err) {
console.log(err)
res.status(500).json({
message: 'Не удалось обновить статью',
});
}
};
105 changes: 105 additions & 0 deletions controllers/UserController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import bcrypt from "bcrypt";
import UserModel from "../models/User.js";
import jwt from "jsonwebtoken";

export const register = async (req, res) => {
try {
const password = req.body.password;
const salt = await bcrypt.genSalt(10);
const hash = await bcrypt.hash(password, salt);

const doc = new UserModel({
email: req.body.email,
userName: req.body.userName,
passwordHash: hash,
avatarUrl: req.body.avatarUrl,
});

const user = await doc.save();

const token = jwt.sign(
{
_id: user._id,
},
'secret123',
{
expiresIn: '30d',
},
);

const {passwordHash, ...userData} = user._doc;

res.json({
...userData,
token,
});
} catch (err) {
console.log(err)
res.status(500).json({
message: 'Не удалось зарегистрировать пользователя',
});
}
};

export const login = async (req, res) => {
try {
const user = await UserModel.findOne({email: req.body.email});

if (!user) {
return res.status(404).json({
message: 'Некорректные данные для авторизации'
});
}

const isValidPass = await bcrypt.compare(req.body.password, user._doc.passwordHash);

if (!isValidPass) {
return res.status(400).json({
message: 'Некорректные данные для авторизации'
});
}

const token = jwt.sign(
{
_id: user._id,
},
'secret123',
{
expiresIn: '30d',
},
);

const {passwordHash, ...userData} = user._doc;

res.json({
...userData,
token,
});

} catch (err) {
console.log(err)
res.status(500).json({
message: 'Не удалось авторизовать пользователя',
});
}
};

export const getMe = async (req, res) => {
try {
const user = await UserModel.findById(req.userId);
if (!user) {
return res.status(404).json({
message: 'Пользователь не найден'
});
}

const {passwordHash, ...userData} = user._doc;

res.json(userData);
} catch (err) {
console.log(err)
res.status(500).json({
message: 'Отказано в доступе',
});
}
};
3 changes: 3 additions & 0 deletions controllers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * as UserController from "./UserController.js";
export * as PostController from "./PostController.js";

63 changes: 63 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import express from "express";
import mongoose from "mongoose";
import multer from "multer";
import cors from 'cors';
import * as path from "path";

import {PostController, UserController} from './controllers/index.js';
import {loginValidation, postCreateValidation, registerValidation} from "./validations.js";
import {checkAuth, handleValidationErrors} from './utils/index.js';

mongoose.connect(
'mongodb+srv://TheKost:AD6-9PP-Vt9-n6D@cluster0.fkbk1nc.mongodb.net/blog?retryWrites=true&w=majority',
).then(() => console.log('DB ok')).catch((err) => console.log('DB error', err));

const app = express();


// Настройки хранения загруженных файлов
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'media/uploads/'); // Папка для хранения загруженных файлов
},
filename: (req, file, cb) => {
const extension = path.extname(file.originalname);
const basename = path.basename(file.originalname, extension);
cb(null, `${basename}-${Date.now()}${extension}`);
},
});

// Загрузчик файла с настройками хранения
const upload = multer({storage});

// Метод для загрузки файла
app.post('/upload', cors(), upload.single('image'), (req, res) => {
// Возвращаем URL загруженной картинки в качестве ответа на запрос
const url = `${req.protocol}://${req.get('host')}/${req.file.path}`;`a`
res.json({url: url});
});

app.use(cors());
app.use(express.json());

app.use('/media', express.static('media'));

app.post('/auth/login', cors(), loginValidation, handleValidationErrors, UserController.login);
app.post('/auth/registration', cors(), registerValidation, handleValidationErrors, UserController.register);
app.get('/auth/me', cors(), checkAuth, UserController.getMe)

// app.get('/tags',cors(), PostController.getLastTags);

app.get('/posts', cors(), PostController.getAll);
app.get('/posts/tags', cors(), PostController.getLastTags);
app.get('/posts/:id', cors(), PostController.getOne);
app.post('/posts', cors(), checkAuth, postCreateValidation, handleValidationErrors, PostController.create);
app.delete('/posts/:id', cors(), checkAuth, PostController.remove);
app.patch('/posts/:id', cors(), checkAuth, postCreateValidation, handleValidationErrors, PostController.update);

app.listen(4444, (err) => {
if (err) {
return console.log(err);
}
console.log(`Server started`);
});
Loading

0 comments on commit efd04ed

Please sign in to comment.