Showing
15 changed files
with
219 additions
and
74 deletions
... | @@ -11,6 +11,7 @@ KHU-Hub repo: [khuhub.khu.ac.kr/2018102216/dev-profile](https://khuhub.khu.ac.kr | ... | @@ -11,6 +11,7 @@ KHU-Hub repo: [khuhub.khu.ac.kr/2018102216/dev-profile](https://khuhub.khu.ac.kr |
11 | - [x] random quotes **_for developers_** to motivate you :sparkles: | 11 | - [x] random quotes **_for developers_** to motivate you :sparkles: |
12 | - [ ] the amount of commits you've done on [GitHub](https://github.com/) at a glance | 12 | - [ ] the amount of commits you've done on [GitHub](https://github.com/) at a glance |
13 | - [ ] your most-contributed project on GitHub | 13 | - [ ] your most-contributed project on GitHub |
14 | +- [x] today's trending repositories on GitHub | ||
14 | <br> | 15 | <br> |
15 | 16 | ||
16 | ### Additional Features | 17 | ### Additional Features | ... | ... |
... | @@ -23,6 +23,7 @@ | ... | @@ -23,6 +23,7 @@ |
23 | "express-session": "^1.17.1", | 23 | "express-session": "^1.17.1", |
24 | "mongoose": "^5.12.9", | 24 | "mongoose": "^5.12.9", |
25 | "morgan": "^1.10.0", | 25 | "morgan": "^1.10.0", |
26 | + "multer": "^1.4.2", | ||
26 | "nodemon": "^2.0.7", | 27 | "nodemon": "^2.0.7", |
27 | "passport": "^0.4.1", | 28 | "passport": "^0.4.1", |
28 | "passport-github2": "^0.1.12", | 29 | "passport-github2": "^0.1.12", | ... | ... |
... | @@ -2,54 +2,157 @@ import axios from "axios"; | ... | @@ -2,54 +2,157 @@ import axios from "axios"; |
2 | import passport from "passport"; | 2 | import passport from "passport"; |
3 | import User from "../models/User"; | 3 | import User from "../models/User"; |
4 | 4 | ||
5 | -const getQuote = async (req,res) =>{ | 5 | +const getQuote = async (req, res) => { |
6 | - const url = "http://quotes.stormconsultancy.co.uk/random.json"; | 6 | + const url = "http://quotes.stormconsultancy.co.uk/random.json"; |
7 | - const quoteData = await axios.get(url).then(function(response){ | 7 | + const quoteData = await axios.get(url).then(function (response) { |
8 | - return response.data; | 8 | + return response.data; |
9 | - }); | 9 | + }); |
10 | - const quote = quoteData.quote; | 10 | + const quote = quoteData.quote; |
11 | - const author = quoteData.author; | 11 | + const author = quoteData.author; |
12 | - return {quote,author}; | 12 | + return { quote, author }; |
13 | -} | 13 | +}; |
14 | 14 | ||
15 | -export const handleHome = async (req,res)=>{ | 15 | +const gitTrend = async (req, res) => { |
16 | - const quote = await getQuote(); | 16 | + const url = |
17 | - res.render("home",{pageTitle:"Home", quote:quote.quote, author:quote.author}); | 17 | + "https://api.trending-github.com/github/repositories?period=daily"; |
18 | -} | 18 | + const trendData = await axios.get(url).then(function (response) { |
19 | + return response.data; | ||
20 | + }); | ||
21 | + const name0 = trendData[0].name; | ||
22 | + const description0 = trendData[0].description; | ||
23 | + const Url0 = trendData[0].url; | ||
24 | + const stars0 = trendData[0].stars; | ||
25 | + const name1 = trendData[1].name; | ||
26 | + const description1 = trendData[1].description; | ||
27 | + const Url1 = trendData[1].url; | ||
28 | + const stars1 = trendData[1].stars; | ||
29 | + const name2 = trendData[2].name; | ||
30 | + const description2 = trendData[2].description; | ||
31 | + const Url2 = trendData[2].url; | ||
32 | + const stars2 = trendData[2].stars; | ||
33 | + | ||
34 | + return { | ||
35 | + name0, | ||
36 | + description0, | ||
37 | + Url0, | ||
38 | + stars0, | ||
39 | + name1, | ||
40 | + description1, | ||
41 | + Url1, | ||
42 | + stars1, | ||
43 | + name2, | ||
44 | + description2, | ||
45 | + Url2, | ||
46 | + stars2, | ||
47 | + }; | ||
48 | +}; | ||
19 | 49 | ||
20 | 50 | ||
21 | -export const getUserDetail = async (req,res) =>{ | ||
22 | - const quote = await getQuote(); | ||
23 | - res.render("userDetail",{pagetTitle:"User Detail", quote:quote.quote, author:quote.author}) | ||
24 | -} | ||
25 | 51 | ||
26 | -export const getEditProfile = (req,res)=> res.render("editProfile",{pageTitle:"Edit Profile"}); | 52 | +export const handleHome = async (req, res) => { |
53 | + const quote = await getQuote(); | ||
54 | + const trend = await gitTrend(); | ||
55 | + res.render("home", { | ||
56 | + pageTitle: "Home", | ||
57 | + quote: quote.quote, | ||
58 | + author: quote.author, | ||
59 | + name0: trend.name0, | ||
60 | + description0: trend.description0, | ||
61 | + Url0: trend.Url0, | ||
62 | + stars0: trend.stars0, | ||
63 | + name1: trend.name1, | ||
64 | + description1: trend.description1, | ||
65 | + Url1: trend.Url1, | ||
66 | + stars1: trend.stars1, | ||
67 | + name2: trend.name2, | ||
68 | + description2: trend.description2, | ||
69 | + Url2: trend.Url2, | ||
70 | + stars2: trend.stars2, | ||
71 | + }); | ||
72 | +}; | ||
27 | 73 | ||
28 | -export const postEditProfile = (req,res) =>{ | 74 | +export const getUserDetail = async (req, res) => { |
29 | - console.log(req.body); | 75 | + const quote = await getQuote(); |
30 | - res.redirect("/users/edit-profile"); | 76 | + res.render("userDetail", { |
77 | + pagetTitle: "User Detail", | ||
78 | + quote: quote.quote, | ||
79 | + author: quote.author, | ||
80 | + }); | ||
31 | }; | 81 | }; |
32 | 82 | ||
83 | +export const getEditProfile = async (req,res)=> { | ||
84 | + const{ | ||
85 | + user:{_id:id} | ||
86 | + } = req; | ||
87 | + try{ | ||
88 | + const user = await User.findById(id); | ||
89 | + if(user.id !== id){ | ||
90 | + throw Error(); | ||
91 | + } else{ | ||
92 | + res.render("editProfile",{pageTitle:"Edit Profile", user}); | ||
93 | + } | ||
94 | + }catch(error){ | ||
95 | + console.log(error); | ||
96 | + } | ||
97 | +}; | ||
33 | 98 | ||
34 | -export const getJoin = (req,res)=>{ | 99 | +export const postEditProfile = async (req,res) =>{ |
35 | - res.render("join",{pageTitle: "Join"}); | 100 | + const { |
101 | + user:{_id:id}, | ||
102 | + body: {name, email, school, blogUrl, tech, career, introduction}, | ||
103 | + file | ||
104 | + } = req; | ||
105 | + try{ | ||
106 | + const updatedUser = await User.findByIdAndUpdate(id, { | ||
107 | + avatarUrl: file ? file.path : req.session.passport.user.avatarUrl, | ||
108 | + name, | ||
109 | + email, | ||
110 | + school, | ||
111 | + blogUrl, | ||
112 | + tech: User.formatTech(tech), | ||
113 | + career: User.formatCareer(career), | ||
114 | + introduction | ||
115 | + }, | ||
116 | + { | ||
117 | + new: true | ||
118 | + }); | ||
119 | + req.session.passport.user = updatedUser; | ||
120 | + res.redirect("/users/edit-profile"); | ||
121 | + }catch(error){ | ||
122 | + console.log(error); | ||
123 | + res.redirect("/"); | ||
124 | + } | ||
36 | }; | 125 | }; |
37 | 126 | ||
38 | -export const getLogin = (req,res)=>{ | 127 | +export const getJoin = (req, res) => { |
39 | - res.render("login",{pageTitle: "Login"}); | 128 | + res.render("join", { pageTitle: "Join" }); |
40 | }; | 129 | }; |
41 | 130 | ||
42 | -export const handleUsers = (req,res)=>{ | 131 | +export const getLogin = (req, res) => { |
43 | - res.render("users",{pageTitle:"Users"}); | 132 | + res.render("login", { pageTitle: "Login" }); |
44 | -} | 133 | +}; |
45 | 134 | ||
46 | -export const githubLogin = passport.authenticate("github", {scope: [ "user:email" ]}); | 135 | +export const handleUsers = (req, res) => { |
136 | + res.render("users", { pageTitle: "Users" }); | ||
137 | +}; | ||
47 | 138 | ||
48 | -export const githubLoginCallback = async (_, __, profile, done) =>{ | 139 | +export const githubLogin = passport.authenticate("github", { |
49 | - const {_json: {id:githubId, login:githubName, avatar_url:avatarUrl, name, email}} = profile; | 140 | + scope: ["user:email"], |
141 | +}); | ||
142 | + | ||
143 | +export const githubLoginCallback = async (_, __, profile, done) => { | ||
144 | + const { | ||
145 | + _json: { | ||
146 | + id: githubId, | ||
147 | + login: githubName, | ||
148 | + avatar_url: avatarUrl, | ||
149 | + name, | ||
150 | + email, | ||
151 | + }, | ||
152 | + } = profile; | ||
50 | 153 | ||
51 | try{ | 154 | try{ |
52 | - const user = await User.findOne({email}); | 155 | + const user = await User.findOne({githubId}); |
53 | if(user){ | 156 | if(user){ |
54 | user.githubId = githubId, | 157 | user.githubId = githubId, |
55 | user.githubName = githubName | 158 | user.githubName = githubName |
... | @@ -70,11 +173,12 @@ export const githubLoginCallback = async (_, __, profile, done) =>{ | ... | @@ -70,11 +173,12 @@ export const githubLoginCallback = async (_, __, profile, done) =>{ |
70 | } | 173 | } |
71 | }; | 174 | }; |
72 | 175 | ||
73 | -export const postGithubLogin = (req,res)=>{ | 176 | +export const postGithubLogin = (req, res) => { |
74 | - const userId = req.user.id; | 177 | + const userId = req.user.id; |
75 | - res.redirect(`/users/${userId}`); | 178 | + res.redirect(`/users/${userId}`); |
76 | -} | 179 | +}; |
77 | 180 | ||
181 | +<<<<<<< HEAD | ||
78 | export const logout = (req,res)=>{ | 182 | export const logout = (req,res)=>{ |
79 | req.logout(); | 183 | req.logout(); |
80 | res.redirect("/"); | 184 | res.redirect("/"); |
... | @@ -89,4 +193,10 @@ const getRepos = async(req,res) =>{ | ... | @@ -89,4 +193,10 @@ const getRepos = async(req,res) =>{ |
89 | const secondRepoName = latelyRepos.[1].name; | 193 | const secondRepoName = latelyRepos.[1].name; |
90 | const firstRepoUrl = latelyRepos.[0].html_url; | 194 | const firstRepoUrl = latelyRepos.[0].html_url; |
91 | const secondRepoUrl = latelyRepos.[1].html_url; | 195 | const secondRepoUrl = latelyRepos.[1].html_url; |
92 | -}; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
196 | +}; | ||
197 | +======= | ||
198 | +export const logout = (req, res) => { | ||
199 | + req.logout(); | ||
200 | + res.redirect("/"); | ||
201 | +}; | ||
202 | +>>>>>>> 29aa84017aef7f3207044abc818143e72cf33907 | ... | ... |
1 | +import multer from "multer"; | ||
2 | + | ||
1 | export const localsMiddleware = (req,res,next) => { | 3 | export const localsMiddleware = (req,res,next) => { |
2 | res.locals.siteName = "Dev Profile"; | 4 | res.locals.siteName = "Dev Profile"; |
3 | res.locals.loggedUser = req.user || null; | 5 | res.locals.loggedUser = req.user || null; |
... | @@ -19,4 +21,11 @@ export const onlyPrivate = (req, res, next) => { | ... | @@ -19,4 +21,11 @@ export const onlyPrivate = (req, res, next) => { |
19 | } else { | 21 | } else { |
20 | res.redirect("/"); | 22 | res.redirect("/"); |
21 | } | 23 | } |
22 | -}; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
24 | +}; | ||
25 | + | ||
26 | +export const uploadFiles = multer({ | ||
27 | + dest:"uploads/", | ||
28 | + limits: { | ||
29 | + fileSize: 3000000 | ||
30 | + } | ||
31 | +}); | ||
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -27,7 +27,7 @@ const UserSchema = new mongoose.Schema({ | ... | @@ -27,7 +27,7 @@ const UserSchema = new mongoose.Schema({ |
27 | }, | 27 | }, |
28 | tech: [{ type: String, trim: true }], | 28 | tech: [{ type: String, trim: true }], |
29 | career: [{ type: String, trim: true }], | 29 | career: [{ type: String, trim: true }], |
30 | - introduction: String, | 30 | + introduction: { type: String, maxLength: 500}, |
31 | createdAt: { | 31 | createdAt: { |
32 | type: Date, | 32 | type: Date, |
33 | default: Date.now | 33 | default: Date.now | ... | ... |
... | @@ -12,9 +12,10 @@ globalRouter.get("/join", onlyPublic, getJoin); | ... | @@ -12,9 +12,10 @@ globalRouter.get("/join", onlyPublic, getJoin); |
12 | globalRouter.get("/login", onlyPublic, getLogin); | 12 | globalRouter.get("/login", onlyPublic, getLogin); |
13 | globalRouter.get("/logout", onlyPrivate, logout); | 13 | globalRouter.get("/logout", onlyPrivate, logout); |
14 | 14 | ||
15 | -globalRouter.get("/auth/github", githubLogin); | 15 | +globalRouter.get("/auth/github", onlyPublic, githubLogin); |
16 | globalRouter.get( | 16 | globalRouter.get( |
17 | "/auth/github/callback", | 17 | "/auth/github/callback", |
18 | + onlyPublic, | ||
18 | passport.authenticate("github",{failureRedirect: "/login"}), | 19 | passport.authenticate("github",{failureRedirect: "/login"}), |
19 | postGithubLogin | 20 | postGithubLogin |
20 | ); | 21 | ); | ... | ... |
1 | import express from "express"; | 1 | import express from "express"; |
2 | import { getEditProfile, getUserDetail, handleUsers, postEditProfile } from "../controllers/userController"; | 2 | import { getEditProfile, getUserDetail, handleUsers, postEditProfile } from "../controllers/userController"; |
3 | -import { onlyPrivate } from "../middlewares"; | 3 | +import { onlyPrivate, uploadFiles } from "../middlewares"; |
4 | - | ||
5 | 4 | ||
6 | const userRouter = express.Router(); | 5 | const userRouter = express.Router(); |
7 | 6 | ||
8 | -userRouter.get("/",handleUsers); | 7 | +userRouter.get("/", handleUsers); |
9 | 8 | ||
10 | userRouter.get("/edit-profile", onlyPrivate, getEditProfile); | 9 | userRouter.get("/edit-profile", onlyPrivate, getEditProfile); |
11 | -userRouter.post("/edit-profile", onlyPrivate, postEditProfile); | 10 | +userRouter.post("/edit-profile", onlyPrivate, uploadFiles.single("photo"),postEditProfile); |
12 | 11 | ||
13 | userRouter.get("/:id", getUserDetail); | 12 | userRouter.get("/:id", getUserDetail); |
14 | 13 | ||
15 | - | ||
16 | -export default userRouter; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
14 | +export default userRouter; | ... | ... |
... | @@ -32,6 +32,7 @@ app.use(passport.initialize()); | ... | @@ -32,6 +32,7 @@ app.use(passport.initialize()); |
32 | app.use(passport.session()); | 32 | app.use(passport.session()); |
33 | 33 | ||
34 | app.use(localsMiddleware); | 34 | app.use(localsMiddleware); |
35 | +app.use("/uploads", express.static("uploads")); | ||
35 | app.use("/", globalRouter); | 36 | app.use("/", globalRouter); |
36 | app.use("/users", userRouter); | 37 | app.use("/users", userRouter); |
37 | 38 | ... | ... |
1 | extends layouts/main | 1 | extends layouts/main |
2 | 2 | ||
3 | block content | 3 | block content |
4 | - .form-container | 4 | + .form-container |
5 | - form(action="/users/edit-profile", method="POST", enctype="application/json") | 5 | + form(action="/users/edit-profile", method="POST", enctype="multipart/form-data") |
6 | + img(src=`/${loggedUser.avatarUrl}`, width="100", height="120") | ||
6 | .fileUpload | 7 | .fileUpload |
7 | - label(for="picture") Picture | 8 | + label(for="photo") Photo |
8 | - input(type="file", id="picture", name="picture", accept="image/*") | 9 | + input(type="file", id="photo", name="photo", accept="image/*") |
9 | - input(type="text", placeholder="Name", name="name") | 10 | + label(for="name") Name |
10 | - input(type="text", placeholder="Github Id", name="githubId") | 11 | + input(type="text", id="name",placeholder="Name", name="name", value=user.name) |
11 | - input(type="email", placeholder="Email", name="email") | 12 | + label(for="email") Email |
12 | - input(type="text", placeholder="School", name="school") | 13 | + input(type="email", id="email", placeholder="Email", name="email", value=user.email) |
13 | - textarea(name="tech", placeholder="Add your Tech") | 14 | + label(for="school") School |
14 | - textarea(name="career", placeholder="Add your Career") | 15 | + input(type="text", id="school",placeholder="School", name="school", value=user.school) |
15 | - textarea(name="introduction", placeholder="Self introduction") | 16 | + label(for="blogUrl") Blog Url |
17 | + input(type="text", id="blogUrl", placeholder="Blog url", name="blogUrl", value=user.blogUrl) | ||
18 | + label(for="tech") Enter your tech skills seperated by comma. ex)react,node | ||
19 | + textarea(name="tech", id="tech", placeholder="Add Tech you can use")=user.tech | ||
20 | + label(for="career") Enter your careers seperated by comma. ex)A company, B competition | ||
21 | + textarea(name="career", id="career", placeholder="Add your Career")=user.career | ||
22 | + label(for="introduction") Self introduction | ||
23 | + textarea(name="introduction", id="introduction", placeholder="Self introduction", maxlength=200)=user.introduction | ||
16 | input(type="submit", value="Update Profile") | 24 | input(type="submit", value="Update Profile") |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -7,7 +7,22 @@ block content | ... | @@ -7,7 +7,22 @@ block content |
7 | h1 -Developer Profile- | 7 | h1 -Developer Profile- |
8 | h2=quote | 8 | h2=quote |
9 | h3=author | 9 | h3=author |
10 | - .home-link | 10 | + |
11 | - a(href="/join") Join | 11 | + if !loggedUser |
12 | - |#{' '} | 12 | + .home-link |
13 | - a(href="/login") Login | 13 | + a(href="/join") Join |
14 | + |#{' '} | ||
15 | + a(href="/login") Login | ||
16 | + else | ||
17 | + a(href=`/users/${loggedUser._id}`) My profile | ||
18 | + | ||
19 | + .gotoTrend(style="border: 1px solid blue;") | ||
20 | + p(style='color: orange;') Trending Repositories: | ||
21 | + br | ||
22 | + a(href=Url0, style={color:'grey'}) | ||
23 | + p=name0+": "+description0+" - "+stars0+" stars" | ||
24 | + a(href=Url1, style={color:'grey'}) | ||
25 | + p=name1+": "+description1+" - "+stars1+" stars" | ||
26 | + a(href=Url2, style={color:'grey'}) | ||
27 | + p=name2+": "+description2+" - "+stars2+" stars" | ||
28 | + | ... | ... |
... | @@ -3,10 +3,9 @@ extends layouts/main | ... | @@ -3,10 +3,9 @@ extends layouts/main |
3 | block content | 3 | block content |
4 | i.fas.fa-location-arrow | 4 | i.fas.fa-location-arrow |
5 | h3 Start with GitHub! | 5 | h3 Start with GitHub! |
6 | - button.login-github | 6 | + a(href="/auth/github") |
7 | - a(href="/auth/github") | 7 | + .login-github |
8 | - span | 8 | + i.fab.fa-github |
9 | - i.fab.fa-github | 9 | + span Join with GitHub |
10 | - |Join with GitHub | ||
11 | 10 | ||
12 | 11 | ||
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -3,10 +3,9 @@ extends layouts/main | ... | @@ -3,10 +3,9 @@ extends layouts/main |
3 | block content | 3 | block content |
4 | i.fas.fa-location-arrow | 4 | i.fas.fa-location-arrow |
5 | h3 Login with GitHub! | 5 | h3 Login with GitHub! |
6 | - button.login-github | 6 | + a(href="/auth/github") |
7 | - a(href="/auth/github") | 7 | + .login-github |
8 | - span | 8 | + i.fab.fa-github |
9 | - i.fab.fa-github | 9 | + span Login with GitHub |
10 | - |Login with GitHub | ||
11 | 10 | ||
12 | 11 | ||
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
1 | -footer.footer | 1 | +footer.footer |
2 | + hr | ||
2 | .footer__icon | 3 | .footer__icon |
3 | i.fas.fa-code-branch | 4 | i.fas.fa-code-branch |
4 | span.footer__text © dev-profile #{new Date().getFullYear()} | 5 | span.footer__text © dev-profile #{new Date().getFullYear()} |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -12,7 +12,9 @@ header.header | ... | @@ -12,7 +12,9 @@ header.header |
12 | 12 | ||
13 | else | 13 | else |
14 | li | 14 | li |
15 | - a(href="/") Home | 15 | + a(href="/") Home |
16 | + li | ||
17 | + a(href=`/users/${loggedUser._id}`) My Profile | ||
16 | li | 18 | li |
17 | a(href="/users/edit-profile") Edit Profile | 19 | a(href="/users/edit-profile") Edit Profile |
18 | li | 20 | li | ... | ... |
-
Please register or login to post a comment