ėėēė ëí ėëĩėžëĄ pug íėžė ë ëë§í ęē―ė°ėë í íëĶŋė ëģėëĨž ęģĩė íĻėžëĄėĻ ëĐėė§ëĨž ëėļ ė ėëĪ.
ëė ėėēė ëí ėëĩėžëĄ redirectëĨž ėŽėĐí ęē―ė°ėë ėŽėĐėėęē ę·ļ ėīė ëĨž ėë ĪėĢžęģ ėķëĪëĐī flash messgeëĨž ėŽėĐí ė ėëĪ.
express-flashëĨž ėĪėđíëĪ.
$ npm i express-flash
flash ëŊļëĪėĻėī import í í ėŽėĐí ė ėëëĄ íëĪ.
ėīëĨž íĩíī flash ëŊļëĪėĻėīë sessionė ė°ęē°íėŽ íīëđ userėęēë§ ëĐėė§ëĨž ëģīėŽėĪ ė ėëĪ.
ėīë ėžíėą ëĐėė§ëĄ íëē ëģīėŽėĢžęģ ëëĐī expressę° cacheėė ė§ėëēëĶ°ëĪ.
// server.js
import session from "express-session";
import flash from "express-flash"; // express-session ëģīëĪ ëĪėė import íīėž íëĪ â
app.use(flash());
req.flash("ëĐėė§ íė
", "ëĐėė§ ëīėĐ");
flash ëŊļëĪėĻėīëĨž ėĪėđíëĐī req.flash() íĻėëĨž ėŽėĐíī falsh messageëĨž ë§ëĪ ė ėëĪ.
ėíĐė ėë§ė ëĐėė§ëĪė ë§ëĪėī ëŊļëĪėĻėīė ėŧĻíļëĄĪëŽė ėķę°íëëĄ íëĪ.
middleware.js
const protectorMiddleware = () => {
if (req.session.loggedIn) {
next();
} else {
req.flash("info", "Not Authorized");
return res.redirect("/login");
}
};
const publicOnlyMiddleware = () => {
if (!req.session.loggedIn) {
next();
} else {
req.flash("info", "Not Authorized");
return res.redirect("/");
}
};
userController.js
export const finishGithubLogin = async (req, res) => {
// ėĪëĩ
if ("access_token" in tokenRequest) {
// ėĪëĩ
// github APIė userė ė íĻí ėīëĐėžėī ėė ė
if (!emailObj) {
req.flash("error", "No valid email.");
return res.redirect("/login");
}
// ėĪëĩ
} else {
// ėĄėļėĪ í í°ėī ėė ė
req.flash("error", "No access token");
return res.redirect("/login");
}
};
// ëĄę·ļėė ė
export const logout = (req, res) => {
req.session.destroy();
req.flash("info", "Bye bye");
return res.redirect("/");
};
// githubëĄ ęģė ë§ë userę° íĻėĪėëëĨž ëģęē―íë Īęģ í ë
export const getChangePassword = async (req, res) => {
if (req.session.user.socialOnly === true) {
req.flash("error", "Can't change password.");
return res.redirect("/");
}
return res.render("change-password", { pageTitle: "Change Password" });
};
// íĻėĪėë ė
ë°ėīíļ ė
export const postChangePassword = async (req, res) => {
// ėĪëĩ
req.flash("info", "Password updated");
return res.redirect("/users/logout");
};
videoController.js
// ėė íë Īë ëđëėĪė ėė ėę° ėë ë
export const getEdit = async (req, res) => {
// ėĪëĩ
if (String(video.owner) !== _id) {
req.flash("error", "Not Authorized");
return res.status(403).redirect("/");
}
// ėĪëĩ
};
// ėė íë Īë ëđëėĪė ėė ėę° ėë ë
export const postEdit = async (req, res) => {
// ėĪëĩ
if (String(video.owner) !== _id) {
req.flash("error", "Not Authorized");
return res.status(403).redirect("/");
}
// ėĪëĩ
};
// ëđëėĪ ėė ė
export const deleteVideo = async (req, res) => {
// ėĪëĩ
if (String(video.owner) !== _id) {
req.flash("error", "Not Authorized");
return res.status(403).redirect("/");
}
// ėĪëĩ
};
req.flash()ëĨž íĩíī ëĐėė§ëĨž ë§ëĪëĐī, íīëđ ëĐėė§ę° ëīęļī messages ëģėę° ë§ëĪėīė§ëĪ.
pug íėžėė messages.key
ę°ė ėŽėĐíī íīëđ ëĐėė§ëĨž ëģīėŽėĪ ė ėëĪ.
ę°ęļ° ëĪëĨļ ëĐėė§ëĪė ę°ė ííëĄ ëģīėŽėĢžęļ° ėíī mixins íīëė message.pug íėžė ėėąí í base.pug íėžė include íëĪ.
message.pug
mixin message(kind, text)
div.message(class=kind)
span=text
base.pug
include mixins/message
doctype html
html(lang="ko")
head
//- ėĪëĩ
body
if (messages.error)
+message("error", messages.error)
if (messages.info)
+message("info", messages.info)
if (messages.success)
+message("success", messages.success)
include partials/header
main
block content
include partials/footer
// styles.scss
@keyframes goAway {
from {
transform: none;
opacity: 1;
}
to {
transform: translateY(-100px);
opacity: 0;
}
}
.message {
position: absolute;
right: 0;
left: 0;
margin: 0 auto;
max-width: 200px;
height: 40px;
line-height: 40px;
text-align: center;
border-radius: 1000px;
animation: goAway 0.5s 3s ease-in-out forwards;
color: white;
&.error {
background-color: $red;
}
&.info {
background-color: $grey;
}
&.success {
background-color: $blue;
}
}
@keyframes ė ëëĐėīė
ėīëĶ {
from {
// ė ëëĐėīė
ėĪí ė ėĪíėž
}
to {
// ė ëëĐėīė
ėĪí í ėĪíėž
}
}
ėĢžėí ė ė keyframesė ë°ëė 'ęĩŽėēīė ėļ ėėđ ę°'ė ė§ė íīėžë§ ė ėė ėžëĄ ėëíëĪë ęēėīëĪ.
ėĶ, ėėđ ę°ė ė ė ë autoëĨž ėŽėĐí ė ėëĪ.
css animation ėīė ëĶŽ (transition, transform, translate, animation, @keyframes) ė°ļęģ
animation: ėīëĶ | ė§ė ėę° | ė§ė° ėę° | ė§í ë°Đė | fill-mode ėėą
fromėė ė§ė° ėę°
ë§íž ėę°ėī ė§ëëĐī, toę° ė§ė í ė§í ë°Đė
ėžëĄ ë°ėíęģ , to ėíę° ė§ė ėę°
ë§íž ėīėīė§ëĪ.
fill-mode ėėą
ė ė ëëĐėīė
ėī ėĪí ė ·íė ëėė ėĪíėžė ė ėĐíë ë°Đëēė ė§ė íëĪ.
forwards
ëĨž ė§ė íëĐī, ė§ė ėę°ėī ęē―ęģžíī ė ëëĐėīė
ėī ëëë to ėíę° ęģė ė ė§ëëĪ.
ėėę° position: absolute
ėíėž ë margin: 0 auto
ëĨž ė§ė íëëžë íīëđ ėėë ėĪė ė ë Žëė§ ėëëĪ.
ėīë íīëđ ėėę° ëļëĄ ë ëēĻ ėėėīëëžë ë§ėđ ėļëžėļ ë ëēĻ ėėėēëž ėŧĻí
ėļ ë§ížė ëëđë§ė ę°ė§ęē ëëĪ.
div {
position: absolute;
right: 0;
margin: 0 auto;
}
position: absolute
ėėëĨž ėĪė ė ë Žíęļ° ėíīėë margin: 0 auto
ę° ëĻđëëĄ left: 0
ęģž right: 0
ė ėķę°íī íīëđ ėėę° ëķëŠĻ ëëđëĨž ëŠĻë ė°Ļė§íęē ë§ëĪėīėž íëĪ.
div {
position: absolute;
right: 0;
left: 0;
margin: 0 auto;
}