26.08.2023
1216
Xoş gəldiniz! Bu bölmədə biz layihəmizə istifadəçi qeydiyyatı, profilinə daxil ola bilməsi, istifadəçilərə xəbər yaratmağa icazə verilməsi kimi funksionallıqları əlavə edəcəyik. Bundan əlavə, istifadəçi vebsayta daxil olduqda navbar'ı uyğun şəkildə dəyişdirəcəyik.
İstifadəçilərin idarə olunması
Əvvəlki bölümdə yaratmış olduğumuz istifadəçilərin qeydiyyatdan keçməsi, daxil olması üçün səhifələrə əlavələr olunacaq. Biz həmçinin verilənlər bazasında istifadəçiləri idarə etmək üçün `Passport.js`-dən istifadə edəcəyik. İstifadəçi profillərinə baxmaq və onlardan çıxmaq da bu bölmədə müzakirə olunacaq mövzulardan biri olacaq.
Navbar tənzimləmələri
İstifadəçi daxil olubsa, “Xəbər Yaz” düyməsi ilə navbar'ı yeniləyəcəyik. Əlavə olaraq, əgər istofadəçi sistemdən çıxsa, o "Daxil ol" və "Qeydiyyat" düymələrinə yönləndirəcəyik. Bu yolla istifadəçilər xəbər yazma icazəsi yalnız daxil olan istifadəçilərə veriləcək.
Xəbərlərin yaradılması
Layihəmizə xəbər yaratma funksionallığı əlavə edəcəyik. İstifadəçilər sadə form vasitəsilə xəbər başlıqlarını və məzmununu daxil edə biləcəklər. Bu məlumat verilənlər bazasında saxlanılacaq və ana səhifədə digər istifadəçilərə göstəriləcək.
Bu bölümdə ələ alacağımız mövzular haqqında qısa məlumatdan sonra növbə ilə həmin hissələri işləməyə başlayaq!
Əvvəlcə istifadəçi modelini yaratmaqla başlayaq. Sonra, `Passport.js` ilə bu modeldən istifadə edərək istifadəçi qeydiyyatını və girişini həyata keçirəcəyik. Bu və əlavə bir neçə paketdən istifadə üçün əvvəlcə həmin paketləri yükləməliyik. `Visual Studio`-dan istifadə ediriksə, `ctrl + ~` və ya `Terminal -> New Terminal` klik edib `npm install express-session passport passport-local passport-local-mongoose` komandasını daxil edirik. Bizə lazım olan paketləri yüklədiyimizə görə istifadəçi modelini yarada bilərik:
models/user.js
javascript
import { Schema, model } from "mongoose";
import passportLocalMongoose from "passport-local-mongoose";
const userSchema = new Schema({
username: String,
email: String,
password: String,
});
userSchema.plugin(passportLocalMongoose);
export const userModel = model("user", userSchema);
Bu modeldə biz `passport-local-mongoose` npm paketin istifadə edərək Passport.js-ə uyğun istifadəçi idarəetməsini təmin edirik. Bu paket istifadəçi adı və şifrə məlumatlarından istifadə edir və avtomatik olaraq şifrələmə və yoxlamanı idarə edir. Pasport.js üçün bəzi konfiqurasiyaları əlavə etmək üçün `config/passport.js` faylını yaradıb kodları əlavə edək:
config/passport.js
javascript
import passport from "passport";
import { Strategy } from "passport-local";
import { userModel } from "../models/user.js";
// Pasport konfiqurasiyası
passport.use(new Strategy(userModel.authenticate()));
passport.serializeUser(userModel.serializeUser());
passport.deserializeUser(userModel.deserializeUser());
export default passport;
Bu konfiqurasiyadan əlavə proqrama session` əlavə olunmalıdır. Session istifadəçilərə müəyyən müddət ərzində müəyyən məlumatlara daxil olmağa imkan verən veb proqramlardakı mexanizmdir. Bu, istifadəçinin brauzeri ilə veb server arasında saxlanılan məlumat anbarıdır. `Session` istifadəçinin məlumatlarını və digər müvəqqəti məlumatlarını saxlayır. express-session modulu Express.js-də sessiyanın idarə edilməsi üçün istifadə olunur. Aşağıda konfiqurasiya faylında `express-session` modulunun necə istifadə oluna biləcəyinə dair bir nümunə verilmişdir:
config/session.js;
javascript
import session from "express-session";
const sessionConfig = {
secret: "secretkey", // Təhlükəsizlik məqsədləri üçün istifadə olunur, daha təhlükəsiz dəyərdən istifadə olunmalıdır.
resave: false,
saveUninitialized: false,
cookie: {
maxAge: 1000 * 60 * 60, // Session müddəti (millisaniyələrlə), məsələn, bir saat
httpOnly: true,
},
};
export default session(sessionConfig);
Son olaraq istifadəçinin giriş edib-etmədiyini bilmək üçün middleware'ə ehtiyyacımız olacaq. Bunun üçün `middleware` qovluğu və içərisində `auth.js` faylını yaradırıq. Daha sonra kodlarımızı əlavə edirik:
middleware/auth.js
javascript
const authMiddleware = (req, res, next) => {
res.locals.currentUser = req.user;
next();
};
export default authMiddleware;
Yuxarıdakı kod parçasında `client`-ə göndərilən `currentUser` dəyərini daha sonra navbar'ı tənzimləmək üçün və digər funksionallıqları əlavə etmək üçün istifadə edəcəyik. Session üçün də konfiqurasiyanı etdikdən sonra `index.js` faylına daxil oluruq. Burada son yazdığımız funksiyaların səhifə marşrutlardan(route) yuxarıda istifadə olunmasına diqqət olunmalıdır:
javascript
// Digər kodlar
import session from "./config/session.js";
import passport from "./config/passport.js";
import authMiddleware from "./middleware/auth.js";
...
// Middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, "public")));
// Session middleware
app.use(session);
// Passport middleware
app.use(passport.initialize());
app.use(passport.session());
app.use(authMiddleware);
İstifadəçilərin qeydiyyatdan keçməsi və daxil olması kimi funksionallıqları əlavə etmək məqsədilə `controllers/user.js` faylına kodlarımızı əlavə edirik:
controllers/user.js
javascript
export const registerHandler = (req, res, next) => {
// Burada qeydiyyat əməliyyatları həyata keçirilir
// Məsələn, req.body məlumatlarından istifadə edərək yeni istifadəçi yarada bilərsiniz
const { username, email, password } = req.body;
const newUser = new userModel({ username, email });
userModel.register(newUser, password, (err) => {
if (err) {
return next(err);
}
res.redirect("/sing-up");
});
export const loginHandler = passport.authenticate("local", {
// Burada giriş əməliyyatları yerinə yetirilir
successRedirect: "/",
failureRedirect: "/sign-up",
failureFlash: true,
});
};
Bu funksiyalar istifadəçi qeydiyyatını və Passport.js ilə girişi idarə edir. passport.authenticate() funksiyası istifadəçinin məlumatlarını yoxlayır və uğurlu giriş edildikdə istifadəçini yönləndirir.
Navbar tənzimləmələri
İstifadəçi sayta uğurla daxil olduqdan sonra navbar'da müəyyən dəyişiklikləri etmək üçün `views/partials/header.ejs` faylına keçid edib əvvəldən yazmış olduğumuz kodları yeniləyirik:
views/partials/header.ejs
html
<header class="header">
<h1 class="display-4 text-center">Xəbər oxuma platforması</h1>
<nav class="navbar navbar-expand-lg navbar-light bg-light px-2">
<div class="d-flex justify-content-between align-items-center container">
<a class="navbar-brand" href="/">Əsas səhifə</a>
<div>
<% if (!currentUser) { %>
<!-- İstifadəçi daxil olmayıbsa -->
<button class="btn bg-secondary">
<a class="text-decoration-none text-white" href="/user/login"
>Login</a
>
</button>
<button class="btn bg-light border">
<a class="text-decoration-none text-black" href="/user/sign-up"
>Sign Up</a
>
</button>
<% } else { %>
<!-- İstifadəçi daxil olduqda -->
<button class="btn bg-secondary">
<a class="text-decoration-none text-white" href="/user/profile"
>Profil</a
>
</button>
<% } %>
</div>
</div>
</nav>
</header>
Hal-hazırda uğurlu şəkildə qeydiyyatdan keçə və sayta daxil ola bilərik. Ancaq istifadəçi məlumatlarını və yazdığı xəbərləri görmək üçün controller/user.js-ə daxil olub `getUserProfile` funksiyasını yeniləyək:
controller/user.js
javascript
// İstifadəçi profilinin səhifəsini göstərir
export const getUserProfile = async (req, res) => {
try {
// Əgər istifadəçi sayta daxil olubsa
if (req.isAuthenticated()) {
const userId = req.user._id;
// İstifadəçi məlumatları
const currentUser = await userModel.findById(userId);
// İstifadəçinin yazdığı xəbərlər
const news = await newsModel.find({ user: userId });
// Profil səhifəsinin renderi
res.render("profile", { currentUser, news });
} else {
// Daxil olmadığı halda istifadəçini uyğun səhifəyə yönləndirilir
res.redirect("/user/login");
}
} catch (err) {
// Xəta baş verdikdə error səhifəsinə yönləndirilir
console.error(err);
res.status(500).render("error", { errorMes
sage: err.message });
}
};
Hal-hazırda istifadəçi öz profilinə daxil olduqda profil məlumatlarına, əvvəlcədən yazmış olduğu xəbərlərə baxa bilər. Bunun üçün `profile.ejs` faylındakı bəzi kodları yeniləmək lazımdır:
profile.ejs
html
...
<div class="col-12 col-sm-6 col-md-8">
<h2>İstifadəçi Profili</h2>
<!-- İstifadəçi profili məlumatları buraya gelecek -->
<% if (currentUser) { %>
<p>Ad: <%= currentUser.username %></p>
<p>Email: <%= currentUser.email %></p>
<a href="/user/logout" class="btn btn-danger mt-3">Çıxış</a>
<% } else { %>
<!-- İstifadəçi giriş etməyibsə -->
<p>Zəhmət olmasa giriş edin</p>
<% } %>
</div>
<div class="col-12 col-sm-6 col-md-4">
<div
class="d-flex justify-content-between align-items-center border-bottom pb-2"
>
<h2>Xəbərlərim</h2>
<a href="/user/create-news" class="btn btn-success">Xəbər yaz</a>
</div>
<% if (news && news.length > 0) { %> <% news.map(({ title, description }) => {
%>
<div class="card my-2">
<div class="card-body">
<h5 class="card-title">
<a href="/single-news/123" class="text-decoration-none text-secondary">
<%= title %>
</a>
</h5>
<p class="card-text"><%= description %></p>
</div>
</div>
<% }); %> <% } else { %>
<p class="my-2">Heç bir xəbər tapılmadı</p>
<% } %>
</div>
Öncəki bölümdə hazırladığımız `create-news.ejs` faylına daxil olduqda, istifadəçi yeni xəbər yaza və paylaşa biləcəkdi. İndi gəlin həmin funksionallığı əlavə edək. Bu hissədə diqqət olunmalı məqam, istifadəçi saytımıza daxil olmayıbsa, başqa sözlə `session` yoxdursa həmin səhifəyə keçid edə bilməz. Bunun əvəzinə login səhifəsinə daxil olub əvvəlcə profilinə daxil olmalıdır. İlk öncə istifadəçinin xəbər yaratmaq üçün daxil olacağı form səhifəsinə yönlənməsi üçün aşağıdakı kodu əlavə edək:
controllers/user.js
javascript
export const getCreateNewsForm = (req, res) => {
if (req.isAuthenticated()) {
res.render("create-news");
} else {
res.redirect("/user/login");
}
};
Yazdığımız funksiya təbiiki `routes/user.js` faylında istifadə olunmalıdır. Son funksionallığı əlavə etməzdən əvvəl verilənlər bazasında məlumatların doğru şəkildə saxlanılmasını təmin etmək üçün modellərimizdə bəzi dəyişiklikləri etmək vacibdir. Aydındır ki, bir xəbər hər hansı bir istifadəçi tərəfindən yazıla bilər. Ona görə də `News` modeli ilə istifadəçi modeli arasında əlaqəni yaratmaq və istifadəçi modelinin bir referansını xəbər modelində saxlamaq lazımdır. Bundan əlavə xəbərin şərhlərini, kimlərin bu xəbəri bəyəndiyini bilmək məqsədilə uğyun dəyərləri daxil etməliyik. Vaxt itirmədən xəbər modelini yeniləyək:
models/news.js
javascript
// Xəbər Modeli
import { Schema, model } from "mongoose";
const newsSchema = new Schema({
title: { type: String, required: true },
description: { type: String, required: true },
date: { type: Date, default: Date.now },
// İstifadəçi referansı (xəbəri kimin yaratdığını göstərmək üçün)
user: { type: Schema.Types.ObjectId, ref: "User", required: true },
// Xəbərlərin şərhləri
comments: [
{
user: { type: Schema.Types.ObjectId, ref: "User", required: true },
content: { type: String, required: true },
date: { type: Date, default: Date.now },
},
],
// Xəbəri bəyənən istifadəçilər
likes: [{ type: Schema.Types.ObjectId, ref: "User" }],
});
export const newsModel = model("News", newsSchema);
Bu modeldə istifadə olunan referanslar bunlardır:
user: Xəbəri yaradan istifadəçinin \_id-sini saxlayır.
comments: Xəbərə edilən şərhləri bildirən massiv. Hər şərhdə istifadəçi \_id, məzmun və tarix məlumatı var.
likes: Xəbəri bəyənən istifadəçilərin identifikatorunu(\_id) saxlayır.
Xəbər modelini yenilədikdən sonra kiçik dəyişikliyimiz etmək üçün istifadəçi modelinə daxil oluruq:
models/user.js
javascript
import { Schema, model } from "mongoose";
import passportLocalMongoose from "passport-local-mongoose";
const userSchema = new Schema({
username: String,
email: String,
password: String,
// İstifadəçini izləyən digər istifadəçilər
followers: [{ type: Schema.Types.ObjectId, ref: "User" }],
});
userSchema.plugin(passportLocalMongoose);
export const userModel = model("user", userSchema);
Modelləri yenilədikdən sonra istifadəçinin xəbər yazması və həmin məlumatların databazada saxlanılmasını təmin etmənin vaxtıdır. Bunun üçün yenidən `controllers/user.js` faylında uyğun metod əlavə olunur. Ümumiyyətlə bu faylda yazmış olduğumuz funksiyaları `routes/user.js` faylında istifadə etməyi unutmayaq:
controllers/user.js
javascript
// Yeni xəbər yaratmaq
export const createNewsHandler = async (req, res) => {
try {
const { title, description } = req.body;
const userId = req.user._id; // daxil olmuş istifadəçinin identifikatoru(_id)
// Xəbərin verilənlər bazasına əlavə olunması
const newNews = new newsModel({
title,
description,
user: userId,
});
await newNews.save();
res.redirect("/");
} catch (error) {
console.error(error);
res.status(500).render("error", { errorMessage: error });
}
};
Son dəyişikliyi etdikdən sonra yazdığımız kodların necə işlədiyiniz test edə bilərik. Gələn bölümdə istifadəçilərin xəbərləri bəyənmə, şərh bildirmə və s. kimi funksionallıqları əlavə edəcəyik. Bu bölümü uğurla başa çatdırdınız! Növbəti bölümdə görüşənədək.
Məqaləni hazırladı: Şamil Vasiyev
Məqaləni təsdiqlədi: Əlinemət İsiyev