Criar um portal de notícias envolve várias etapas, desde a concepção até a implementação. Aqui estão algumas etapas e considerações que podem ajudar você a começar:
- Tipo de Notícias: Especifique se o portal abordará notícias locais, globais, específicas de uma indústria, etc.
- Público-Alvo: Identifique a quem o portal se destina, como estudantes, profissionais, entusiastas, etc.
- Análise da Concorrência: Pesquise outros portais de notícias para entender o que funciona e o que pode ser aprimorado.
- Estrutura de Conteúdo: Crie categorias claras para organizar as notícias, como política, tecnologia, esportes, entretenimento, etc.
- Desenvolvimento Próprio ou Plataforma Pronta: Decida se você deseja criar o portal do zero ou usar plataformas de gerenciamento de conteúdo (CMS) como WordPress, Joomla, etc.
- Layout Atraente e Funcional: Certifique-se de que o design seja atraente e fácil de navegar em diferentes dispositivos (computadores, tablets, smartphones).
- Sistema de Gerenciamento de Conteúdo (CMS): Facilita a adição, edição e remoção de notícias.
- Pesquisa: Implemente uma função de pesquisa para facilitar a localização de notícias específicas.
- Comentários e Interação: Permita que os usuários comentem nas notícias e compartilhem em redes sociais.
- Publicidade: Considere espaços publicitários para gerar receita.
- Assinaturas Premium: Se aplicável, ofereça um modelo de assinatura premium para conteúdo exclusivo.
- URLs Amigáveis: Utilize URLs descritivas para melhorar a visibilidade nos motores de busca.
- Meta Descriptions e Títulos: Otimize meta descriptions e títulos para aumentar a relevância nas pesquisas.
- Certificado SSL: Garanta a segurança do portal com um certificado SSL para proteger a comunicação entre o servidor e o usuário.
- Teste Cross-Browser: Verifique se o portal funciona corretamente em diferentes navegadores.
- Solicite Feedback: Faça testes beta e peça feedback dos usuários para melhorias.
- Lançamento Estratégico: Planeje um lançamento eficaz, destacando recursos únicos.
- Estratégias de Marketing: Utilize mídias sociais, e-mail marketing e outras estratégias para promover o portal.
- Mantenha Conteúdo Atualizado: Regularmente adicione notícias e atualize informações relevantes.
- Aprimoramentos Constantes: Esteja preparado para fazer melhorias com base no feedback e nas tendências do mercado.
Lembre-se de adaptar essas diretrizes conforme as necessidades específicas do seu projeto. Boa sorte com o seu portal de notícias!
- Criação de dois schemas do mongodb atlas com a conexão pegando os dados do dotenv, sendo um schema authors com name, email, password, is_active, outro categories com name, slug, is_active, e news com title, slug_title, category com chave estrangeira da outra tabela, author tambpem com chave do outro banco, image, createat, updateat, is_active
Claro, vou orientá-lo na criação dos dois schemas no MongoDB Atlas usando o Node.js com o auxílio do pacote mongoose para modelagem e manipulação de dados MongoDB, além do dotenv para gerenciamento de variáveis de ambiente.
Primeiro, certifique-se de instalar os pacotes necessários usando o npm (ou yarn):
$ npm install mongoose dotenv
Agora, você pode criar os schemas para os autores (authors), categorias (categories) e notícias (news). Crie um arquivo chamado models.js
:
// models.js
const mongoose = require('mongoose');
// Conectando ao MongoDB usando dotenv
require('dotenv').config();
mongoose.connect(process.env.MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
// Definindo o esquema para autores
const authorSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true },
password: { type: String, required: true },
is_active: { type: Boolean, default: true },
});
// Definindo o esquema para categorias
const categorySchema = new mongoose.Schema({
name: { type: String, required: true },
slug: { type: String, required: true },
is_active: { type: Boolean, default: true },
});
// Definindo o esquema para notícias
const newsSchema = new mongoose.Schema({
title: { type: String, required: true },
slug_title: { type: String, required: true },
category: { type: mongoose.Schema.Types.ObjectId, ref: 'Category', required: true },
author: { type: mongoose.Schema.Types.ObjectId, ref: 'Author', required: true },
image: { type: String }, // Caminho para a imagem (opcional)
created_at: { type: Date, default: Date.now },
updated_at: { type: Date, default: Date.now },
is_active: { type: Boolean, default: true },
});
// Criando os modelos
const Author = mongoose.model('Author', authorSchema);
const Category = mongoose.model('Category', categorySchema);
const News = mongoose.model('News', newsSchema);
module.exports = { Author, Category, News };
Certifique-se de criar um arquivo .env
na raiz do seu projeto com a URI do MongoDB Atlas:
MONGODB_URI=seu_link_do_mongodb_atlas
Agora, em seus outros arquivos, você pode importar os modelos onde precisar:
// Seu arquivo que utiliza os modelos
const { Author, Category, News } = require('./models');
// Agora você pode usar Author, Category e News para interagir com o MongoDB Atlas
Este é um exemplo básico para começar. Certifique-se de adaptar conforme necessário para atender aos requisitos específicos do seu projeto. Se precisar de mais alguma coisa ou tiver dúvidas específicas, estou aqui para ajudar!
Crie agora o form com ejs que na rota /login mostre o form para login da dashboard
Para criar um formulário de login com EJS (Embedded JavaScript) em uma rota /login
, você precisará seguir algumas etapas. Primeiro, certifique-se de ter o pacote express
instalado:
$ npm install express ejs
Agora, crie um arquivo app.js
para configurar o servidor Express:
javascript// app.js
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const app = express();
// Configuração do EJS
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// Configuração do bodyParser para lidar com dados do formulário
app.use(bodyParser.urlencoded({ extended: true }));
// Rota para exibir o formulário de login
app.get('/login', (req, res) => {
res.render('login');
});
// Inicialização do servidor
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Servidor rodando na porta ${PORT}`);
});
Em seguida, crie uma pasta views
na mesma pasta do seu app.js
, e dentro dela, crie um arquivo chamado login.ejs
:
html<!-- views/login.ejs -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
</head>
<body>
<h2>Login</h2>
<form action="/login" method="post">
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
<br>
<label for="password">Senha:</label>
<input type="password" id="password" name="password" required>
<br>
<button type="submit">Entrar</button>
</form>
</body>
</html>
Este é um formulário básico que captura o e-mail e a senha. No entanto, é importante notar que este formulário não está lidando com autenticação real neste momento. Você precisará implementar a lógica de autenticação no backend.
No seu arquivo app.js
, você pode adicionar a lógica de tratamento do formulário de login. Vou criar um exemplo básico usando o Express para isso:
javascript// ...
// Rota para lidar com o envio do formulário de login
app.post('/login', (req, res) => {
const { email, password } = req.body;
// Adicione aqui a lógica de autenticação (exemplo simples)
if (email === '[email protected]' && password === 'sua_senha') {
res.send('Login bem-sucedido!'); // Você pode redirecionar para a dashboard ou fazer o que for necessário
} else {
res.send('Credenciais inválidas. Tente novamente.');
}
});
// ...
Lembre-se de que esta é uma lógica de autenticação muito básica e insegura. Em um ambiente de produção, você deve usar bibliotecas de autenticação seguras, como Passport.js, e armazenar senhas de maneira segura (usando hash e salt, por exemplo).
Espero que isso ajude! Adaptaremos conforme suas necessidades específicas.
Adapte para usar o passport e a tabela user criada anteriormente
Claro, vou ajudá-lo a adaptar o código para usar o Passport.js e a tabela de usuários (autores) que você criou anteriormente. Certifique-se de ter o passport
e passport-local
instalados:
bashnpm install passport passport-local
Aqui está como você pode adaptar o código para incluir o Passport.js:
- Primeiro, atualize o arquivo
app.js
para incluir o Passport.js:
javascript// app.js
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const session = require('express-session');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const { Author } = require('./models');
const app = express();
// Configuração do EJS
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// Configuração do bodyParser para lidar com dados do formulário
app.use(bodyParser.urlencoded({ extended: true }));
// Configuração da sessão e Passport.js
app.use(session({ secret: 'seu_segredo', resave: false, saveUninitialized: false }));
app.use(passport.initialize());
app.use(passport.session());
// Configuração da estratégia local do Passport.js
passport.use(new LocalStrategy({ usernameField: 'email' }, async (email, password, done) => {
try {
const user = await Author.findOne({ email });
if (!user || !user.validPassword(password)) {
return done(null, false, { message: 'Credenciais inválidas. Tente novamente.' });
}
return done(null, user);
} catch (error) {
return done(error);
}
}));
// Serialização e desserialização do usuário
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser(async (id, done) => {
try {
const user = await Author.findById(id);
done(null, user);
} catch (error) {
done(error);
}
});
// Rota para exibir o formulário de login
app.get('/login', (req, res) => {
res.render('login');
});
// Rota para lidar com o envio do formulário de login
app.post('/login', passport.authenticate('local', {
successRedirect: '/dashboard',
failureRedirect: '/login',
failureFlash: true,
}));
// Rota protegida para a dashboard
app.get('/dashboard', (req, res) => {
if (req.isAuthenticated()) {
res.send(`Bem-vindo à dashboard, ${req.user.name}!`);
} else {
res.redirect('/login');
}
});
// ...
// Inicialização do servidor
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Servidor rodando na porta ${PORT}`);
});
- Adapte seu modelo
Author
para incluir um métodovalidPassword
para verificar a senha:
javascript// models.js
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
// ... (seu código existente)
// Adicione o método validPassword ao esquema do Author
authorSchema.methods.validPassword = function (password) {
return bcrypt.compareSync(password, this.password);
};
// ...
module.exports = { Author, Category, News };
- Certifique-se de adicionar o pacote
bcrypt
para lidar com a comparação de senhas:
bashnpm install bcrypt
Este exemplo usa a estratégia local do Passport.js para autenticação, mas você pode adaptá-lo para usar outras estratégias, como OAuth, dependendo das suas necessidades. Lembre-se de que este é um exemplo básico, e em um ambiente de produção, você deve considerar práticas de segurança adicionais.
Agora crie os forms para insert, update e delete dos users, categories e news com bloqueio de acesso direto, sendo acessados apenas no dashboard e se tiver logad
Para criar formulários de inserção, atualização e exclusão de usuários, categorias e notícias, com bloqueio de acesso direto e acesso restrito ao dashboard, você pode seguir estas etapas.
-
Atualização do
app.js
para Adicionar Rota de Dashboard Protegida:Adicione middleware para verificar se o usuário está autenticado antes de acessar as rotas relacionadas às operações CRUD. Também adicione rotas para as páginas de formulários (insert/update/delete).
javascript// app.js
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const session = require('express-session');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const { Author, Category, News } = require('./models');
const app = express();
// Configuração do EJS
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// Configuração do bodyParser para lidar com dados do formulário
app.use(bodyParser.urlencoded({ extended: true }));
// Configuração da sessão e Passport.js
app.use(session({ secret: 'seu_segredo', resave: false, saveUninitialized: false }));
app.use(passport.initialize());
app.use(passport.session());
// ... (código de configuração do Passport.js)
// Middleware para verificar autenticação antes de acessar rotas protegidas
const isAuthenticated = (req, res, next) => {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/login');
};
// Rota protegida para a dashboard
app.get('/dashboard', isAuthenticated, (req, res) => {
res.send(`Bem-vindo à dashboard, ${req.user.name}!`);
});
// Rotas para formulários de usuários, categorias e notícias (CRUD)
app.get('/dashboard/user/add', isAuthenticated, (req, res) => {
res.render('userAdd');
});
app.get('/dashboard/user/edit/:id', isAuthenticated, (req, res) => {
// Lógica para preencher o formulário de edição com dados existentes
const userId = req.params.id;
// ... (consulta ao banco de dados para obter os dados do usuário)
res.render('userEdit', { user: /* dados do usuário */ });
});
app.get('/dashboard/user/delete/:id', isAuthenticated, (req, res) => {
// Lógica para preencher o formulário de exclusão com dados existentes
const userId = req.params.id;
// ... (consulta ao banco de dados para obter os dados do usuário)
res.render('userDelete', { user: /* dados do usuário */ });
});
// ... (rotas semelhantes para categorias e notícias)
// Inicialização do servidor
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Servidor rodando na porta ${PORT}`);
});
-
Criar Páginas EJS para os Formulários:
Crie páginas EJS (
userAdd.ejs
,userEdit.ejs
,userDelete.ejs
, e semelhantes para categorias e notícias) com formulários HTML correspondentes para inserção, atualização e exclusão.
html<!-- views/userAdd.ejs -->
<!-- Formulário para adicionar usuário -->
<form action="/dashboard/user/add" method="post">
<!-- Campos do formulário -->
<button type="submit">Adicionar Usuário</button>
</form>
html<!-- views/userEdit.ejs -->
<!-- Formulário para editar usuário -->
<form action="/dashboard/user/edit/<%= user._id %>" method="post">
<!-- Campos do formulário preenchidos com dados existentes -->
<button type="submit">Atualizar Usuário</button>
</form>
html<!-- views/userDelete.ejs -->
<!-- Formulário para excluir usuário -->
<form action="/dashboard/user/delete/<%= user._id %>" method="post">
<!-- Campos do formulário preenchidos com dados existentes -->
<button type="submit">Excluir Usuário</button>
</form>
-
Adicionar Rotas de Manipulação de Dados no
app.js
:Adicione rotas para manipular dados no banco de dados, incluindo adição, atualização e exclusão de usuários, categorias e notícias.
javascript// app.js
// ...
// Rota para adicionar usuário
app.post('/dashboard/user/add', isAuthenticated, async (req, res) => {
// Lógica para adicionar usuário ao banco de dados
// ...
res.redirect('/dashboard');
});
// Rota para editar usuário
app.post('/dashboard/user/edit/:id', isAuthenticated, async (req, res) => {
// Lógica para editar usuário no banco de dados
// ...
res.redirect('/dashboard');
});
// Rota para excluir usuário
app.post('/dashboard/user/delete/:id', isAuthenticated, async (req, res) => {
// Lógica para excluir usuário do banco de dados
// ...
res.redirect('/dashboard');
});
// ... (rotas semelhantes para categorias e notícias)
// ...
Lembre-se de que estas são estruturas básicas e é necessário adaptá-las às suas necessidades específicas. Além disso, considere adicionar medidas de segurança adicionais, como validação de entrada e manipulação adequada de erros.
Separe as rotas num arquivo a parte numa pasta routes e adapte tudo para funcionar
Vamos dividir as rotas em arquivos separados e organizar a estrutura do projeto. Primeiro, crie uma pasta chamada routes
e, dentro dela, crie os arquivos dashboard.js
e auth.js
.
routes/dashboard.js
- Rotas para o Dashboard e Operações CRUD:
javascript// routes/dashboard.js
const express = require('express');
const router = express.Router();
const isAuthenticated = require('../middleware/auth'); // Middleware para verificar autenticação
// Rota para o Dashboard
router.get('/', isAuthenticated, (req, res) => {
res.send(`Bem-vindo à dashboard, ${req.user.name}!`);
});
// Rotas para Usuários
router.get('/user/add', isAuthenticated, (req, res) => {
res.render('userAdd');
});
router.get('/user/edit/:id', isAuthenticated, (req, res) => {
// Lógica para preencher o formulário de edição com dados existentes
const userId = req.params.id;
// ... (consulta ao banco de dados para obter os dados do usuário)
res.render('userEdit', { user: /* dados do usuário */ });
});
router.get('/user/delete/:id', isAuthenticated, (req, res) => {
// Lógica para preencher o formulário de exclusão com dados existentes
const userId = req.params.id;
// ... (consulta ao banco de dados para obter os dados do usuário)
res.render('userDelete', { user: /* dados do usuário */ });
});
// ... (rotas semelhantes para categorias e notícias)
module.exports = router;
routes/auth.js
- Rotas de Autenticação:
javascript// routes/auth.js
const express = require('express');
const passport = require('passport');
const router = express.Router();
// Rota para exibir o formulário de login
router.get('/login', (req, res) => {
res.render('login');
});
// Rota para lidar com o envio do formulário de login
router.post('/login', passport.authenticate('local', {
successRedirect: '/dashboard',
failureRedirect: '/auth/login',
failureFlash: true,
}));
module.exports = router;
- Atualize o
app.js
para usar esses arquivos de rota:
javascript// app.js
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const session = require('express-session');
const passport = require('passport');
const { Author, Category, News } = require('./models');
const app = express();
// Configuração do EJS
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// Configuração do bodyParser para lidar com dados do formulário
app.use(bodyParser.urlencoded({ extended: true }));
// Configuração da sessão e Passport.js
app.use(session({ secret: 'seu_segredo', resave: false, saveUninitialized: false }));
app.use(passport.initialize());
app.use(passport.session());
// Configuração da estratégia local do Passport.js
passport.use(new LocalStrategy({ usernameField: 'email' }, async (email, password, done) => {
try {
const user = await Author.findOne({ email });
if (!user || !user.validPassword(password)) {
return done(null, false, { message: 'Credenciais inválidas. Tente novamente.' });
}
return done(null, user);
} catch (error) {
return done(error);
}
}));
// Serialização e desserialização do usuário
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser(async (id, done) => {
try {
const user = await Author.findById(id);
done(null, user);
} catch (error) {
done(error);
}
});
// Middleware para verificar autenticação antes de acessar rotas protegidas
const isAuthenticated = (req, res, next) => {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/auth/login');
};
// Rotas para autenticação
const authRoutes = require('./routes/auth');
app.use('/auth', authRoutes);
// Rotas para o Dashboard e CRUD
const dashboardRoutes = require('./routes/dashboard');
app.use('/dashboard', isAuthenticated, dashboardRoutes);
// ...
// Inicialização do servidor
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Servidor rodando na porta ${PORT}`);
});
Essa estrutura organiza melhor o código, mantendo as responsabilidades separadas. O arquivo auth.js
gerencia as rotas de autenticação, enquanto dashboard.js
cuida das operações CRUD e da exibição do dashboard.
Lembre-se de ajustar esses arquivos de acordo com suas necessidades específicas.
Agora vamos criar a visualização das noticias com bootstrap 5 e ejs na rota / bem como em /news/categoria-x listar as noticias da categoria x, y, etc
Ótimo! Vamos criar as visualizações das notícias usando Bootstrap 5 e EJS.
-
Criar a Página EJS para Visualização de Notícias:
Crie um arquivo chamado
news.ejs
na pastaviews
:
html<!-- views/news.ejs -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Notícias</title>
<!-- Bootstrap 5 CSS (Você pode baixar e referenciar localmente ou usar uma CDN) -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<h2>Todas as Notícias</h2>
<!-- Loop através de notícias para exibi-las -->
<% for (const newsItem of newsList) { %>
<div class="card my-3">
<div class="card-body">
<h5 class="card-title"><%= newsItem.title %></h5>
<p class="card-text"><%= newsItem.content %></p>
</div>
</div>
<% } %>
</div>
<!-- Bootstrap 5 JS (Você pode baixar e referenciar localmente ou usar uma CDN) -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
-
Atualizar a Rota no
app.js
para Renderizar a Página de Notícias:Adicione uma rota para renderizar a página de notícias na raiz ("/"):
javascript// app.js
// ...
// Rota para exibir todas as notícias
app.get('/', async (req, res) => {
try {
const newsList = await News.find({ is_active: true }).exec();
res.render('news', { newsList });
} catch (error) {
console.error(error);
res.status(500).send('Erro ao recuperar notícias.');
}
});
// ...
-
Criar a Página EJS para Visualizar Notícias por Categoria:
Crie um arquivo chamado
categoryNews.ejs
na pastaviews
:
html<!-- views/categoryNews.ejs -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Notícias por Categoria</title>
<!-- Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<h2>Notícias da Categoria: <%= categoryName %></h2>
<!-- Loop através de notícias para exibi-las -->
<% for (const newsItem of newsList) { %>
<div class="card my-3">
<div class="card-body">
<h5 class="card-title"><%= newsItem.title %></h5>
<p class="card-text"><%= newsItem.content %></p>
</div>
</div>
<% } %>
</div>
<!-- Bootstrap 5 JS -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
-
Atualizar a Rota no
app.js
para Renderizar a Página de Notícias por Categoria:Adicione uma rota para renderizar a página de notícias por categoria ("/news/:category"):
javascript// app.js
// ...
// Rota para exibir notícias por categoria
app.get('/news/:category', async (req, res) => {
const categoryName = req.params.category;
try {
const newsList = await News.find({ category: categoryName, is_active: true }).exec();
res.render('categoryNews', { categoryName, newsList });
} catch (error) {
console.error(error);
res.status(500).send('Erro ao recuperar notícias por categoria.');
}
});
// ...
Essas alterações permitem que você exiba todas as notícias na rota principal ("/") e as notícias de uma categoria específica na rota ("/news/:category"). Certifique-se de adaptar o código conforme necessário para atender às suas necessidades específicas de banco de dados e modelos de dados.
Se precisar fazer upload da imagem para a pasta /public/assets/img para cada noticia como ficaria, salvando o nome da imagem no banco e upload dela?
Para implementar o upload de imagens para as notícias e salvar o nome da imagem no banco de dados, você pode seguir os passos abaixo. Vou incluir a utilização do pacote multer
para lidar com o upload de arquivos no Express.
-
Instale o pacote
multer
:bashnpm install multer
-
Atualize o
app.js
para configurar o middleware Multer e as rotas de upload de imagens:javascript// app.js const express = require('express'); const path = require('path'); const bodyParser = require('body-parser'); const session = require('express-session'); const passport = require('passport'); const multer = require('multer'); // Pacote para lidar com upload de arquivos const { Author, Category, News } = require('./models'); const app = express(); // Configuração do EJS app.set('view engine', 'ejs'); app.set('views', path.join(__dirname, 'views')); // Configuração do bodyParser para lidar com dados do formulário app.use(bodyParser.urlencoded({ extended: true })); // Configuração da sessão e Passport.js app.use(session({ secret: 'seu_segredo', resave: false, saveUninitialized: false })); app.use(passport.initialize()); app.use(passport.session()); // Configuração do middleware Multer para upload de imagens const storage = multer.diskStorage({ destination: './public/assets/img', filename: function (req, file, cb) { cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname)); } }); const upload = multer({ storage: storage }); // ... (Configuração do Passport.js, rotas existentes, etc.) // Rota para exibir todas as notícias app.get('/', async (req, res) => { try { const newsList = await News.find({ is_active: true }).exec(); res.render('news', { newsList }); } catch (error) { console.error(error); res.status(500).send('Erro ao recuperar notícias.'); } }); // Rota para exibir notícias por categoria app.get('/news/:category', async (req, res) => { // ... (código existente) }); // Rota para renderizar formulário de adição de notícia app.get('/dashboard/news/add', isAuthenticated, (req, res) => { res.render('newsAdd'); }); // Rota para lidar com envio do formulário de adição de notícia app.post('/dashboard/news/add', isAuthenticated, upload.single('image'), async (req, res) => { try { const { title, content, category } = req.body; const image = req.file.filename; // Nome do arquivo de imagem // Crie a notícia no banco de dados await News.create({ title, content, category, image, created_at: new Date(), updated_at: new Date(), is_active: true }); res.redirect('/dashboard'); } catch (error) { console.error(error); res.status(500).send('Erro ao adicionar notícia.'); } }); // ... (Outras rotas para edição, exclusão, etc.) // Rota para servir arquivos estáticos (imagens) app.use('/assets', express.static(path.join(__dirname, 'public/assets'))); // Inicialização do servidor const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Servidor rodando na porta ${PORT}`); });
-
Crie a Página EJS para o Formulário de Adição de Notícias:
Crie um arquivo chamado
newsAdd.ejs
na pastaviews
:html<!-- views/newsAdd.ejs --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Adicionar Notícia</title> <!-- Bootstrap 5 CSS --> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container mt-5"> <h2>Adicionar Notícia</h2> <form action="/dashboard/news/add" method="post" enctype="multipart/form-data"> <div class="mb-3"> <label for="title" class="form-label">Título:</label> <input type="text" class="form-control" id="title" name="title" required> </div> <div class="mb-3"> <label for="content" class="form-label">Conteúdo:</label> <textarea class="form-control" id="content" name="content" rows="4" required></textarea> </div> <div class="mb-3"> <label for="category" class="form-label">Categoria:</label> <input type="text" class="form-control" id="category" name="category" required> </div> <div class="mb-3"> <label for="image" class="form-label">Imagem:</label> <input type="file" class="form-control" id="image" name="image" accept="image/*" required> </div> <button type="submit" class="btn btn-primary">Adicionar Notícia</button> </form> </div> <!-- Bootstrap 5 JS --> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script> </body> </html>
Agora, quando você acessar /dashboard/news/add
, verá um formulário para adicionar notícias, incluindo o upload de imagens. Certifique-se de adaptar conforme necessário para atender às suas necessidades específicas.
E foi alterado a view das noticias para exibir a imagem?
Peço desculpas pela omissão. Vamos ajustar a visualização das notícias para incluir a exibição da imagem.
-
Atualize a Página EJS para Visualizar Notícias (
news.ejs
):Edite o arquivo
news.ejs
para incluir a exibição de imagens associadas às notícias:html<!-- views/news.ejs --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Notícias</title> <!-- Bootstrap 5 CSS --> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container mt-5"> <h2>Todas as Notícias</h2> <!-- Loop através de notícias para exibi-las --> <% for (const newsItem of newsList) { %> <div class="card my-3"> <!-- Exibição da imagem --> <img src="/assets/img/<%= newsItem.image %>" class="card-img-top" alt="<%= newsItem.title %>"> <div class="card-body"> <h5 class="card-title"><%= newsItem.title %></h5> <p class="card-text"><%= newsItem.content %></p> </div> </div> <% } %> </div> <!-- Bootstrap 5 JS --> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script> </body> </html>
Agora, ao percorrer a lista de notícias, o código inclui uma tag
<img>
para exibir a imagem associada à notícia.
Certifique-se de adaptar conforme necessário, especialmente se precisar incluir títulos, descrições ou outros detalhes específicos para a exibição da imagem.
Tem mais alguma dica para esse projeto? em resumo, quero logar e inserir os dados dos 3 bancos. Daí visualizar as notícias diariamente
Certamente! Aqui estão algumas dicas adicionais para aprimorar seu projeto:
-
Segurança:
Certifique-se de implementar boas práticas de segurança, como hash de senhas, validação de entrada adequada, prevenção contra injeção de código, e proteção contra CSRF (Cross-Site Request Forgery). Use pacotes como
bcrypt
para hash de senhas e considere implementar HTTPS para comunicação segura. -
Validação de Entrada:
Adicione validação de entrada para garantir que os dados inseridos estejam corretos. Você pode usar bibliotecas como
express-validator
para facilitar a validação e tratamento de erros. -
Ordenação e Paginação:
Implemente ordenação e paginação para exibição de notícias. Isso pode ser útil conforme a quantidade de notícias cresce, proporcionando uma melhor experiência de usuário.
-
Gestão de Sessão:
Além da autenticação, considere adicionar funcionalidades como lembrar-me, redefinição de senha e gestão de sessões. Pacotes como
express-session
econnect-mongo
podem ser úteis. -
Design Responsivo:
Certifique-se de que o design do seu portal seja responsivo, proporcionando uma boa experiência de usuário em dispositivos móveis e tablets. O Bootstrap 5 já oferece uma base sólida para design responsivo.
-
Manutenção de Código:
Mantenha o código limpo e organizado. Considere dividir o código em módulos para facilitar a manutenção. Ferramentas como ESLint e Prettier podem ajudar a manter a consistência no código.
-
Testes Unitários e Integração:
Implemente testes unitários e de integração para garantir que seu aplicativo funcione conforme o esperado. Ferramentas como
Jest
eSupertest
podem ser úteis para isso. -
Monitoramento e Logging:
Adicione funcionalidades de logging para rastrear eventos importantes. Além disso, considere a implementação de monitoramento de desempenho e erros usando ferramentas como
New Relic
ouSentry
. -
Deploy e Escalabilidade:
Ao implantar seu aplicativo, escolha uma plataforma adequada e configure adequadamente para escalabilidade. Ferramentas como
PM2
ouDocker
podem ser úteis. -
Política de Cache:
Considere a implementação de uma política de cache para otimizar o desempenho, especialmente para notícias que não mudam com frequência.
Lembre-se de que essas são apenas sugestões gerais e você pode ajustar de acordo com os requisitos específicos do seu projeto. Boa sorte com seu portal de notícias!
Faltou isso, implemente a páginação por favor na view das noticias
Certamente! Para implementar a paginação na visualização de notícias, você pode usar o pacote mongoose-paginate-v2
que adiciona suporte à paginação em consultas MongoDB. Vamos passar pelas alterações necessárias no código.
-
Instale o pacote
mongoose-paginate-v2
:bashnpm install mongoose-paginate-v2
-
Atualize o Modelo
News
para Usar Paginação:javascript// models/news.js const mongoose = require('mongoose'); const mongoosePaginate = require('mongoose-paginate-v2'); const newsSchema = new mongoose.Schema({ title: String, content: String, category: String, image: String, created_at: { type: Date, default: Date.now }, updated_at: { type: Date, default: Date.now }, is_active: { type: Boolean, default: true }, }); newsSchema.plugin(mongoosePaginate); const News = mongoose.model('News', newsSchema); module.exports = News;
-
Atualize a Rota para Exibir Todas as Notícias (
app.js
):javascript// app.js const express = require('express'); const path = require('path'); const bodyParser = require('body-parser'); const session = require('express-session'); const passport = require('passport'); const mongoose = require('mongoose'); const mongoosePaginate = require('mongoose-paginate-v2'); const { Author, Category, News } = require('./models'); const app = express(); // ... (Configurações do EJS, bodyParser, Passport, etc.) // Rota para exibir todas as notícias com paginação app.get('/', async (req, res) => { const page = parseInt(req.query.page) || 1; const limit = 10; // Número de notícias por página try { const result = await News.paginate({ is_active: true }, { page, limit }); res.render('news', { newsList: result.docs, currentPage: result.page, totalPages: result.totalPages }); } catch (error) { console.error(error); res.status(500).send('Erro ao recuperar notícias.'); } }); // ... (Outras rotas) // ...
-
Atualize a Página EJS para Visualizar Notícias (
news.ejs
):html<!-- views/news.ejs --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Notícias</title> <!-- Bootstrap 5 CSS --> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container mt-5"> <h2>Todas as Notícias</h2> <!-- Loop através de notícias para exibi-las --> <% for (const newsItem of newsList) { %> <div class="card my-3"> <!-- Exibição da imagem --> <img src="/assets/img/<%= newsItem.image %>" class="card-img-top" alt="<%= newsItem.title %>"> <div class="card-body"> <h5 class="card-title"><%= newsItem.title %></h5> <p class="card-text"><%= newsItem.content %></p> </div> </div> <% } %> <!-- Paginação --> <nav aria-label="Page navigation"> <ul class="pagination"> <% for (let i = 1; i <= totalPages; i++) { %> <li class="page-item <%= i === currentPage ? 'active' : '' %>"> <a class="page-link" href="?page=<%= i %>"><%= i %></a> </li> <% } %> </ul> </nav> </div> <!-- Bootstrap 5 JS --> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script> </body> </html>
Aqui, a variável
currentPage
contém o número da página atual, etotalPages
contém o número total de páginas disponíveis. O loop de paginação cria links para cada página.
Certifique-se de ajustar os valores conforme necessário, especialmente a quantidade de notícias exibidas por página. Essa implementação oferece uma base para adicionar e expandir a funcionalidade de paginação no seu projeto.
Também implemente encriptação da senha de users ao ser inserida no banco de dados bem como o login use o hash para comparar e logar
Para encriptar a senha dos usuários antes de armazená-la no banco de dados e para comparar as senhas durante o processo de login, você pode utilizar o pacote bcrypt
. O bcrypt
é uma biblioteca popular para hashing de senhas em Node.js.
Vamos integrar o bcrypt
no seu projeto.
-
Instale o pacote
bcrypt
:bashnpm install bcrypt
-
Atualize o Modelo
Author
para Usar obcrypt
:javascript// models/author.js const mongoose = require('mongoose'); const bcrypt = require('bcrypt'); const authorSchema = new mongoose.Schema({ name: String, email: { type: String, unique: true }, password: String, is_active: { type: Boolean, default: true }, }); // Antes de salvar, hash da senha authorSchema.pre('save', async function (next) { try { const saltRounds = 10; const hashedPassword = await bcrypt.hash(this.password, saltRounds); this.password = hashedPassword; next(); } catch (error) { next(error); } }); const Author = mongoose.model('Author', authorSchema); module.exports = Author;
-
Atualize a Rota de Registro de Usuário (
/dashboard/user/add
) para Usar a Senha Criptografada:javascript// app.js // ... // Rota para renderizar formulário de adição de usuário app.get('/dashboard/user/add', isAuthenticated, (req, res) => { res.render('userAdd'); }); // Rota para lidar com envio do formulário de adição de usuário app.post('/dashboard/user/add', isAuthenticated, async (req, res) => { try { const { name, email, password } = req.body; // Crie o usuário no banco de dados await Author.create({ name, email, password, is_active: true }); res.redirect('/dashboard'); } catch (error) { console.error(error); res.status(500).send('Erro ao adicionar usuário.'); } }); // ...
-
Atualize a Rota de Login para Verificar a Senha Criptografada:
javascript// app.js // ... // Rota para exibir o formulário de login app.get('/auth/login', (req, res) => { res.render('login'); }); // Rota para lidar com o envio do formulário de login app.post('/auth/login', passport.authenticate('local', { successRedirect: '/dashboard', failureRedirect: '/auth/login', failureFlash: true, })); // ...
javascript// passport.js const passport = require('passport'); const LocalStrategy = require('passport-local').Strategy; const bcrypt = require('bcrypt'); const { Author } = require('./models'); passport.use(new LocalStrategy({ usernameField: 'email' }, async (email, password, done) => { try { const user = await Author.findOne({ email }); if (!user) { return done(null, false, { message: 'Credenciais inválidas. Tente novamente.' }); } const isPasswordValid = await bcrypt.compare(password, user.password); if (!isPasswordValid) { return done(null, false, { message: 'Credenciais inválidas. Tente novamente.' }); } return done(null, user); } catch (error) { return done(error); } }));
Agora, a senha dos usuários será criptografada antes de ser armazenada no banco de dados. Durante o login, a senha fornecida será comparada com a senha criptografada no banco de dados para autenticação. Certifique-se de adaptar conforme necessário para atender às suas necessidades específicas.
Tem como separar as lógicas de tudo q foi visto? rotas num arquivo, models em outro, middlewares, controllers, etc? usar SOLID
Sim, é uma prática bastante recomendada separar a lógica do projeto em diferentes módulos para melhorar a organização e manutenção do código. Vamos criar uma estrutura básica usando SOLID, separando as rotas, models, middlewares e controllers.
-
Estrutura de Diretórios:
Crie a seguinte estrutura de diretórios:
bash/src /controllers /middlewares /models /routes app.js
-
Controllers:
Em
src/controllers
, crie arquivos para cada controlador:javascript// src/controllers/userController.js const { Author } = require('../models'); class UserController { async addUser(req, res) { try { const { name, email, password } = req.body; await Author.create({ name, email, password, is_active: true }); res.redirect('/dashboard'); } catch (error) { console.error(error); res.status(500).send('Erro ao adicionar usuário.'); } } } module.exports = new UserController();
-
Models:
Mantenha seus modelos em
src/models
:javascript// src/models/author.js const mongoose = require('mongoose'); const bcrypt = require('bcrypt'); const authorSchema = new mongoose.Schema({ name: String, email: { type: String, unique: true }, password: String, is_active: { type: Boolean, default: true }, }); authorSchema.pre('save', async function (next) { try { const saltRounds = 10; const hashedPassword = await bcrypt.hash(this.password, saltRounds); this.password = hashedPassword; next(); } catch (error) { next(error); } }); const Author = mongoose.model('Author', authorSchema); module.exports = Author;
-
Middlewares:
Em
src/middlewares
, você pode ter middlewares reutilizáveis:javascript// src/middlewares/authMiddleware.js module.exports = { isAuthenticated(req, res, next) { if (req.isAuthenticated()) { return next(); } res.redirect('/auth/login'); } };
-
Rotas:
Em
src/routes
, crie arquivos para cada conjunto de rotas:javascript// src/routes/userRoutes.js const express = require('express'); const { isAuthenticated } = require('../middlewares/authMiddleware'); const UserController = require('../controllers/userController'); const router = express.Router(); router.get('/dashboard/user/add', isAuthenticated, (req, res) => { res.render('userAdd'); }); router.post('/dashboard/user/add', isAuthenticated, UserController.addUser); module.exports = router;
-
App.js Principal:
O
app.js
principal pode ser mantido na raiz do projeto:javascript// app.js const express = require('express'); const path = require('path'); const bodyParser = require('body-parser'); const session = require('express-session'); const passport = require('passport'); const mongoose = require('mongoose'); const { Author } = require('./src/models'); const userRoutes = require('./src/routes/userRoutes'); const app = express(); // Configuração do EJS, bodyParser, etc. // ... // Configuração do Passport.js, rotas existentes, etc. // ... // Rotas de usuário app.use(userRoutes); // ... // Inicialização do servidor const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Servidor rodando na porta ${PORT}`); });
Certifique-se de ajustar os caminhos dos módulos conforme necessário. Essa estrutura proporciona uma melhor organização e facilita a expansão do projeto.