Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
F
final-exam
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Nawasan Wisitsingkhon
final-exam
Commits
9c4b08df
Commit
9c4b08df
authored
Sep 30, 2023
by
Nawasan Wisitsingkhon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
finish state: login front and back;
parent
69925dae
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
238 additions
and
37 deletions
+238
-37
.env.example
.env.example
+2
-1
UserController.js
app/controllers/UserController.js
+39
-0
web.js
app/routes/web.js
+1
-0
Navbar.js
src/components/Navbar.js
+44
-33
jwttoken.js
src/components/lib/jwttoken.js
+9
-0
userCookie.js
src/components/lib/userCookie.js
+6
-0
_app.js
src/pages/_app.js
+13
-0
login.js
src/pages/login.js
+108
-0
logout.js
src/pages/logout.js
+12
-0
register.js
src/pages/register.js
+4
-3
No files found.
.env.example
View file @
9c4b08df
...
@@ -3,5 +3,5 @@
...
@@ -3,5 +3,5 @@
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
JWT_TOKEN=
DATABASE_URL="mysql://<username>:<password>@localhost:3306/<db_name>?schema=public"
DATABASE_URL="mysql://<username>:<password>@localhost:3306/<db_name>?schema=public"
\ No newline at end of file
app/controllers/UserController.js
View file @
9c4b08df
import
{
Request
,
Response
}
from
"express"
;
import
{
Request
,
Response
}
from
"express"
;
import
{
SHA1
}
from
"crypto-js"
;
import
{
SHA1
}
from
"crypto-js"
;
import
db
from
"../models/prismaClient"
;
import
db
from
"../models/prismaClient"
;
import
{
JwtGenerate
}
from
"@/components/lib/jwttoken"
;
const
UserController
=
{
const
UserController
=
{
/**
/**
...
@@ -62,6 +63,44 @@ const UserController = {
...
@@ -62,6 +63,44 @@ const UserController = {
});
});
}
}
},
},
/**
*
* @param {Request} req
* @param {Response} res
*/
async
login
(
req
,
res
)
{
try
{
let
{
username
,
password
}
=
req
.
body
;
if
(
!
(
username
&&
password
))
throw
202
;
password
=
SHA1
(
password
).
toString
();
let
user
=
await
db
.
user
.
findFirst
({
where
:
{
AND
:
{
username
}
},
});
if
(
!
user
)
throw
203
;
if
(
user
.
password
!==
password
)
throw
203
;
let
token
=
JwtGenerate
({
id
:
user
.
id
,
name
:
user
.
name
,
email
:
user
.
email
,
phone
:
user
.
phone
,
photo
:
user
.
photo
,
username
:
user
.
username
,
rank
:
user
.
rank
,
});
return
res
.
json
({
status
:
201
,
token
,
message
:
"login success"
});
}
catch
(
err
)
{
if
(
err
===
203
)
return
res
.
json
({
status
:
203
,
message
:
"usrname or password is wrong"
,
});
else
if
(
err
===
202
)
res
.
json
({
status
:
202
,
message
:
"error data emty"
,
req
:
req
.
body
});
else
{
res
.
json
({
status
:
200
,
err
,
message
:
"error something"
});
}
}
},
};
};
export
default
UserController
;
export
default
UserController
;
app/routes/web.js
View file @
9c4b08df
...
@@ -5,6 +5,7 @@ const route = express.Router();
...
@@ -5,6 +5,7 @@ const route = express.Router();
route
.
get
(
"/"
,
WelcomeController
.
index
);
route
.
get
(
"/"
,
WelcomeController
.
index
);
route
.
post
(
"/user/auth"
,
UserController
.
login
);
route
.
post
(
"/user"
,
UserController
.
create
);
route
.
post
(
"/user"
,
UserController
.
create
);
route
.
get
(
"/user"
,
(
req
,
res
)
=>
{
route
.
get
(
"/user"
,
(
req
,
res
)
=>
{
res
.
json
({
res
.
json
({
...
...
src/components/Navbar.js
View file @
9c4b08df
...
@@ -13,17 +13,11 @@ import Menu from "@mui/material/Menu";
...
@@ -13,17 +13,11 @@ import Menu from "@mui/material/Menu";
import
MenuIcon
from
"@mui/icons-material/Menu"
;
import
MenuIcon
from
"@mui/icons-material/Menu"
;
import
SearchIcon
from
"@mui/icons-material/Search"
;
import
SearchIcon
from
"@mui/icons-material/Search"
;
import
AccountCircle
from
"@mui/icons-material/AccountCircle"
;
import
AccountCircle
from
"@mui/icons-material/AccountCircle"
;
import
MailIcon
from
"@mui/icons-material/Mail"
;
import
{
Divider
}
from
"@mui/material"
;
import
List
from
"@mui/material/List"
;
import
{
ListItem
}
from
"@mui/material"
;
import
{
ListItemButton
}
from
"@mui/material"
;
import
{
ListItemIcon
}
from
"@mui/material"
;
import
InboxIcon
from
"@mui/icons-material/MoveToInbox"
;
import
ListItemText
from
"@mui/material/ListItemText"
;
import
ShoppingCart
from
"@mui/icons-material/ShoppingCart"
;
import
ShoppingCart
from
"@mui/icons-material/ShoppingCart"
;
import
{
UserContext
}
from
"@/pages/_app"
;
import
{
UserContext
}
from
"@/pages/_app"
;
import
Link
from
"next/link"
;
import
Link
from
"next/link"
;
import
{
Favorite
}
from
"@mui/icons-material"
;
import
{
Logout
}
from
"@mui/icons-material"
;
const
Search
=
styled
(
"div"
)(({
theme
})
=>
({
const
Search
=
styled
(
"div"
)(({
theme
})
=>
({
position
:
"relative"
,
position
:
"relative"
,
...
@@ -65,26 +59,6 @@ const StyledInputBase = styled(InputBase)(({ theme }) => ({
...
@@ -65,26 +59,6 @@ const StyledInputBase = styled(InputBase)(({ theme }) => ({
},
},
}));
}));
const
drawer
=
(
<
div
>
<
Toolbar
/>
<
Divider
/>
<
List
>
{[
"Inbox"
,
"Starred"
,
"Send email"
,
"Drafts"
].
map
((
text
,
index
)
=>
(
<
ListItem
key
=
{
index
}
disablePadding
>
<
ListItemButton
>
<
ListItemIcon
>
{
index
%
2
===
0
?
<
InboxIcon
/>
:
<
MailIcon
/>
}
<
/ListItemIcon
>
<
ListItemText
primary
=
{
text
}
/
>
<
/ListItemButton
>
<
/ListItem
>
))}
<
/List
>
{
/* <Divider /> */
}
<
/div
>
);
function
Navbar
(
props
)
{
function
Navbar
(
props
)
{
const
user
=
useContext
(
UserContext
);
const
user
=
useContext
(
UserContext
);
const
{
window
}
=
props
;
const
{
window
}
=
props
;
...
@@ -143,7 +117,21 @@ function Navbar(props) {
...
@@ -143,7 +117,21 @@ function Navbar(props) {
const
MenuList
=
user
?.
value
?.
name
const
MenuList
=
user
?.
value
?.
name
?
[
?
[
{
{
id
:
0
,
label
:
"สินค้าที่ชอบ"
,
link
:
"/wishlist"
,
element
:
(
<
IconButton
size
=
"large"
aria
-
label
=
"show 4 new mails"
color
=
"inherit"
>
<
Badge
badgeContent
=
{
4
}
color
=
"error"
>
<
Favorite
/>
<
/Badge
>
<
/IconButton
>
),
},
{
label
:
"ตระกร้า"
,
label
:
"ตระกร้า"
,
link
:
"/cart"
,
link
:
"/cart"
,
element
:
(
element
:
(
...
@@ -159,8 +147,7 @@ function Navbar(props) {
...
@@ -159,8 +147,7 @@ function Navbar(props) {
),
),
},
},
{
{
id
:
1
,
label
:
user
.
value
.
name
,
label
:
"โปรไฟล์"
,
link
:
"/profile"
,
link
:
"/profile"
,
element
:
(
element
:
(
<
IconButton
<
IconButton
...
@@ -175,15 +162,39 @@ function Navbar(props) {
...
@@ -175,15 +162,39 @@ function Navbar(props) {
<
/IconButton
>
<
/IconButton
>
),
),
},
},
{
label
:
"ออกจากระบบ"
,
link
:
"/logout"
,
element
:
(
<
IconButton
size
=
"large"
aria
-
label
=
"show 4 new mails"
color
=
"inherit"
>
<
Badge
color
=
"error"
>
<
Logout
/>
<
/Badge
>
<
/IconButton
>
),
},
]
]
:
[
:
[
{
{
id
:
0
,
id
:
0
,
label
:
"Register"
,
label
:
"Register"
,
element
:
<
span
className
=
"inline-block mx-3 hover:underline"
>
Register
<
/span>
,
element
:
(
<
span
className
=
"inline-block mx-3 hover:underline"
>
Register
<
/span
>
),
link
:
"/register"
,
link
:
"/register"
,
},
},
{
id
:
1
,
lable
:
"Login"
,
element
:
<
span
className
=
"inline-block mx-3 hover:underline"
>
Login
<
/span>, link: "/
login
" },
{
id
:
1
,
lable
:
"Login"
,
element
:
(
<
span
className
=
"inline-block mx-3 hover:underline"
>
Login
<
/span
>
),
link
:
"/login"
,
},
];
];
const
mobileMenuId
=
"primary-search-account-menu-mobile"
;
const
mobileMenuId
=
"primary-search-account-menu-mobile"
;
...
...
src/components/lib/jwttoken.js
0 → 100644
View file @
9c4b08df
import
jwt
from
"jsonwebtoken"
;
/**
*
* @param {{id: number, name: string, email: string, phone: string, photo: string, username: string }} data
*/
export
const
JwtGenerate
=
(
data
)
=>
{
let
token
=
jwt
.
sign
(
data
,
process
.
env
.
JWT_TOKEN
,
{
algorithm
:
"HS256"
});
return
token
;
};
src/components/lib/user.js
→
src/components/lib/user
Cookie
.js
View file @
9c4b08df
...
@@ -7,6 +7,12 @@ class userCookie {
...
@@ -7,6 +7,12 @@ class userCookie {
isLogin
()
{
isLogin
()
{
return
!!
this
.
token
;
return
!!
this
.
token
;
}
}
store
(
token
)
{
Cookies
.
set
(
"token"
,
token
);
}
delete
()
{
Cookies
.
remove
(
"token"
);
}
}
}
export
default
userCookie
;
export
default
userCookie
;
src/pages/_app.js
View file @
9c4b08df
...
@@ -5,12 +5,25 @@ import "@fontsource/roboto/500.css";
...
@@ -5,12 +5,25 @@ import "@fontsource/roboto/500.css";
import
"@fontsource/roboto/700.css"
;
import
"@fontsource/roboto/700.css"
;
import
{
createContext
,
useState
,
useEffect
}
from
"react"
;
import
{
createContext
,
useState
,
useEffect
}
from
"react"
;
import
UserLayout
from
"@/components/layout/UserLayout"
;
import
UserLayout
from
"@/components/layout/UserLayout"
;
import
userCookie
from
"@/components/lib/userCookie"
;
// axios.defaults.baseURL = ""
// axios.defaults.baseURL = ""
export
const
UserContext
=
createContext
(
null
);
export
const
UserContext
=
createContext
(
null
);
export
default
function
App
({
Component
,
pageProps
})
{
export
default
function
App
({
Component
,
pageProps
})
{
const
[
user
,
setUser
]
=
useState
({});
const
[
user
,
setUser
]
=
useState
({});
useEffect
(()
=>
{
const
usrcookie
=
new
userCookie
();
let
token
=
usrcookie
.
token
.
split
(
"."
)[
1
];
if
(
token
)
{
let
user_info
=
JSON
.
parse
(
atob
(
token
));
user_info
.
token
=
usrcookie
.
token
;
setUser
(
user_info
);
console
.
log
(
user_info
);
}
},
[]);
return
(
return
(
<
UserContext
.
Provider
value
=
{{
value
:
user
,
set
:
setUser
}}
>
<
UserContext
.
Provider
value
=
{{
value
:
user
,
set
:
setUser
}}
>
<
UserLayout
>
<
UserLayout
>
...
...
src/pages/login.js
0 → 100644
View file @
9c4b08df
import
{
Box
,
Button
,
Divider
,
Grid
,
TextField
}
from
"@mui/material"
;
import
{
Snackbar
}
from
"@mui/material"
;
import
React
from
"react"
;
import
{
useContext
}
from
"react"
;
import
{
UserContext
}
from
"./_app"
;
import
{
Container
}
from
"@mui/material"
;
import
{
Google
}
from
"@mui/icons-material"
;
import
{
useState
}
from
"react"
;
import
axios
from
"axios"
;
import
userCookie
from
"@/components/lib/userCookie"
;
export
default
function
Login
()
{
const
user
=
useContext
(
UserContext
);
const
[
errorMessage
,
setErrorMessage
]
=
useState
(
""
);
const
[
successMessage
,
setSuccessMessage
]
=
useState
(
""
);
const
[
username
,
setUsername
]
=
useState
(
""
);
const
[
password
,
setPassword
]
=
useState
(
""
);
if
(
user
.
value
?.
name
)
return
(
<
div
>
<
h3
>
{
user
.
value
.
name
}
<
/h3
>
<
/div
>
);
/**
*
* @param {FormDataEvent} e
*/
async
function
onSubmitForm
(
e
)
{
e
.
preventDefault
();
let
response
=
await
axios
.
post
(
"/api/user/auth"
,
{
username
,
password
});
console
.
log
(
response
.
data
);
if
(
response
.
data
.
status
===
201
)
{
const
usrsto
=
new
userCookie
();
usrsto
.
store
(
response
.
data
.
token
);
window
.
location
.
href
=
'/'
}
else
if
(
response
.
data
.
status
===
203
)
{
setErrorMessage
(
"ชื่อผู้ใช้หรือระหัสผ่านไม่ถูกต้อง"
);
setTimeout
(()
=>
{
setErrorMessage
(
""
);
},
3000
);
}
}
return
(
<
div
>
<
Container
>
<
Snackbar
ContentProps
=
{{
className
:
"bg-red-500"
}}
anchorOrigin
=
{{
horizontal
:
"center"
,
vertical
:
"top"
}}
open
=
{
!!
errorMessage
.
length
}
message
=
{
errorMessage
}
/
>
<
Snackbar
ContentProps
=
{{
className
:
"bg-green-500"
}}
anchorOrigin
=
{{
horizontal
:
"center"
,
vertical
:
"top"
}}
open
=
{
!!
successMessage
.
length
}
message
=
{
successMessage
}
/
>
<
Grid
container
>
<
Grid
item
lg
=
{
3
}
md
=
{
0
}
><
/Grid
>
<
Grid
item
lg
=
{
6
}
md
=
{
12
}
>
<
div
className
=
"border border-red-500 bg-white py-3 text-center rounded-lg"
>
<
form
onSubmit
=
{
onSubmitForm
}
className
=
""
>
<
Box
component
=
{
"h2"
}
className
=
"text-gray-700"
>
เข้าสู่ระบบ
<
/Box
>
<
TextField
label
=
"username"
variant
=
"standard"
className
=
"mx-3 my-1"
value
=
{
username
}
onChange
=
{(
e
)
=>
setUsername
(
e
.
target
.
value
)}
required
/>
<
TextField
label
=
"password"
type
=
"password"
variant
=
"standard"
className
=
"mx-3 my-1"
value
=
{
password
}
onChange
=
{(
e
)
=>
setPassword
(
e
.
target
.
value
)}
required
/>
<
div
className
=
"text-right px-10 sm:px-16"
>
<
Button
className
=
"my-5 text-lg"
variant
=
"contained"
type
=
"submit"
>
เข้าสู่ระบบ
<
/Button
>
<
/div
>
<
/form
>
<
Divider
/>
<
Box
component
=
{
"h4"
}
>
หรือเข้าสู่ระบบด้วยบัญชี
google
<
/Box
>
<
button
className
=
"bg-white rounded-full border-none hover:shadow-md shadow-gray-400 duration-300 hover:-translate-y-1 cursor-pointer hover:scale-105"
>
<
Google
color
=
"primary"
fontSize
=
"large"
/>
<
/button
>
<
/div
>
<
/Grid
>
<
Grid
item
lg
=
{
3
}
md
=
{
0
}
><
/Grid
>
<
/Grid
>
<
/Container
>
<
/div
>
);
}
src/pages/logout.js
0 → 100644
View file @
9c4b08df
import
userCookie
from
"@/components/lib/userCookie"
;
import
{
useRouter
}
from
"next/router"
;
import
React
from
"react"
;
export
default
function
Logout
()
{
React
.
useEffect
(()
=>
{
const
usr
=
new
userCookie
();
usr
.
delete
();
window
.
location
.
href
=
'/'
},
[]);
return
<
div
>
Logout
<
/div>
;
}
src/pages/register.js
View file @
9c4b08df
...
@@ -70,13 +70,13 @@ export default function Login() {
...
@@ -70,13 +70,13 @@ export default function Login() {
<
Snackbar
<
Snackbar
ContentProps
=
{{
className
:
"bg-red-500"
}}
ContentProps
=
{{
className
:
"bg-red-500"
}}
anchorOrigin
=
{{
horizontal
:
"center"
,
vertical
:
"top"
}}
anchorOrigin
=
{{
horizontal
:
"center"
,
vertical
:
"top"
}}
open
=
{
errorMessage
.
length
}
open
=
{
!!
errorMessage
.
length
}
message
=
{
errorMessage
}
message
=
{
errorMessage
}
/
>
/
>
<
Snackbar
<
Snackbar
ContentProps
=
{{
className
:
"bg-green-500"
}}
ContentProps
=
{{
className
:
"bg-green-500"
}}
anchorOrigin
=
{{
horizontal
:
"center"
,
vertical
:
"top"
}}
anchorOrigin
=
{{
horizontal
:
"center"
,
vertical
:
"top"
}}
open
=
{
successMessage
.
length
}
open
=
{
!!
successMessage
.
length
}
message
=
{
successMessage
}
message
=
{
successMessage
}
/
>
/
>
<
Grid
container
>
<
Grid
container
>
...
@@ -136,6 +136,7 @@ export default function Login() {
...
@@ -136,6 +136,7 @@ export default function Login() {
className
=
"mx-3 my-1"
className
=
"mx-3 my-1"
value
=
{
password
}
value
=
{
password
}
onChange
=
{(
e
)
=>
setPassword
(
e
.
target
.
value
)}
onChange
=
{(
e
)
=>
setPassword
(
e
.
target
.
value
)}
required
/>
/>
<
div
className
=
"text-right px-10 sm:px-16"
>
<
div
className
=
"text-right px-10 sm:px-16"
>
<
Button
<
Button
...
@@ -149,7 +150,7 @@ export default function Login() {
...
@@ -149,7 +150,7 @@ export default function Login() {
<
/form
>
<
/form
>
<
Divider
/>
<
Divider
/>
<
Box
component
=
{
"h4"
}
>
หรือสมัครด้วยบัญชี
google
<
/Box
>
<
Box
component
=
{
"h4"
}
>
หรือสมัครด้วยบัญชี
google
<
/Box
>
<
button
className
=
"bg-white rounded-full border-none hover:shadow-md shadow-gray-400 duration-300 hover:-translate-y-1"
>
<
button
className
=
"bg-white rounded-full border-none hover:shadow-md shadow-gray-400 duration-300 hover:-translate-y-1
cursor-pointer hover:scale-105
"
>
<
Google
color
=
"primary"
fontSize
=
"large"
/>
<
Google
color
=
"primary"
fontSize
=
"large"
/>
<
/button
>
<
/button
>
<
/div
>
<
/div
>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment