Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
H
haiyen-payment
Overview
Overview
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
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Giang Tran
haiyen-payment
Commits
162461d0
Commit
162461d0
authored
Aug 29, 2026
by
tdgiang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add self-service change-password for logged-in accounts
parent
41ae2a28
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
129 additions
and
0 deletions
+129
-0
adminAuth.server.controller.js
app/controllers/adminAuth.server.controller.js
+30
-0
admin.server.routes.js
app/routes/admin.server.routes.js
+4
-0
change-password.server.view.html
app/views/admin/change-password.server.view.html
+95
-0
No files found.
app/controllers/adminAuth.server.controller.js
View file @
162461d0
...
...
@@ -122,3 +122,33 @@ exports.resetAccountPassword = function (req, res) {
});
});
};
exports
.
changePasswordForm
=
function
(
req
,
res
)
{
res
.
render
(
"admin/change-password"
,
{
error
:
null
,
success
:
false
});
};
exports
.
changePassword
=
function
(
req
,
res
)
{
var
currentPassword
=
String
(
req
.
body
.
currentPassword
||
""
);
var
newPassword
=
String
(
req
.
body
.
newPassword
||
""
);
AdminUser
.
findById
(
req
.
session
.
userId
,
function
(
err
,
user
)
{
if
(
err
)
{
console
.
error
(
"changePassword: DB error:"
,
err
.
message
);
return
res
.
status
(
503
).
render
(
"admin/change-password"
,
{
error
:
"Hệ thống đang bận, vui lòng thử lại sau"
,
success
:
false
});
}
if
(
!
user
||
!
passwordHash
.
compare
(
currentPassword
,
user
.
passwordHash
))
{
return
res
.
render
(
"admin/change-password"
,
{
error
:
"Mật khẩu hiện tại không đúng"
,
success
:
false
});
}
if
(
!
newPassword
)
{
return
res
.
render
(
"admin/change-password"
,
{
error
:
"Vui lòng nhập mật khẩu mới"
,
success
:
false
});
}
user
.
passwordHash
=
passwordHash
.
hash
(
newPassword
);
user
.
save
(
function
(
saveErr
)
{
if
(
saveErr
)
{
console
.
error
(
"changePassword: DB error saving:"
,
saveErr
.
message
);
return
res
.
status
(
500
).
render
(
"admin/change-password"
,
{
error
:
"Lỗi cơ sở dữ liệu"
,
success
:
false
});
}
return
res
.
render
(
"admin/change-password"
,
{
error
:
null
,
success
:
true
});
});
});
};
app/routes/admin.server.routes.js
View file @
162461d0
...
...
@@ -18,6 +18,10 @@ module.exports = function (app) {
app
.
route
(
"/admin/accounts/:id/toggle"
).
post
(
requireLogin
,
requireAdmin
,
adminAuth
.
toggleAccount
);
app
.
route
(
"/admin/accounts/:id/reset-password"
).
post
(
requireLogin
,
requireAdmin
,
adminAuth
.
resetAccountPassword
);
app
.
route
(
"/admin/account/password"
)
.
get
(
requireLogin
,
adminAuth
.
changePasswordForm
)
.
post
(
requireLogin
,
adminAuth
.
changePassword
);
app
.
route
(
"/admin/transactions"
)
.
get
(
requireLogin
,
admin
.
listTransactions
)
.
post
(
requireLogin
,
admin
.
createTransaction
);
...
...
app/views/admin/change-password.server.view.html
0 → 100644
View file @
162461d0
<!DOCTYPE html>
<html
lang=
"vi"
>
<head>
<meta
charset=
"utf-8"
>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1"
>
<title>
Đổi mật khẩu
</title>
<link
rel=
"preconnect"
href=
"https://fonts.googleapis.com"
>
<link
rel=
"preconnect"
href=
"https://fonts.gstatic.com"
crossorigin
>
<link
href=
"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
rel=
"stylesheet"
>
<style>
:root
{
--color-bg
:
#F1F5F9
;
--color-surface
:
#FFFFFF
;
--color-primary
:
#1E40AF
;
--color-primary-hover
:
#1D4ED8
;
--color-text
:
#0F172A
;
--color-text-muted
:
#64748B
;
--color-border
:
#E2E8F0
;
--color-danger-bg
:
#FEF2F2
;
--color-danger-border
:
#FECACA
;
--color-success-bg
:
#F0FDF4
;
--color-success-border
:
#BBF7D0
;
--radius
:
10px
;
--shadow-card
:
0
1px
2px
rgba
(
15
,
23
,
42
,
0.04
),
0
8px
24px
rgba
(
15
,
23
,
42
,
0.06
);
}
*
{
box-sizing
:
border-box
;
}
body
{
margin
:
0
;
min-height
:
100vh
;
background
:
var
(
--color-bg
);
font-family
:
'Inter'
,
-apple-system
,
BlinkMacSystemFont
,
'Segoe UI'
,
Roboto
,
Helvetica
,
Arial
,
sans-serif
;
color
:
var
(
--color-text
);
display
:
flex
;
justify-content
:
center
;
padding
:
40px
20px
;
}
.page
{
width
:
100%
;
max-width
:
420px
;
}
.nav
{
display
:
flex
;
gap
:
16px
;
font-size
:
13px
;
margin-bottom
:
20px
;
color
:
var
(
--color-text-muted
);
}
.nav
a
{
color
:
inherit
;
text-decoration
:
none
;
font-weight
:
500
;
}
.nav
a
:hover
{
color
:
var
(
--color-primary
);
}
.card
{
background
:
var
(
--color-surface
);
border
:
1px
solid
var
(
--color-border
);
border-radius
:
var
(
--radius
);
box-shadow
:
var
(
--shadow-card
);
padding
:
32px
;
}
h1
{
font-size
:
20px
;
font-weight
:
700
;
letter-spacing
:
-0.01em
;
margin
:
0
0
20px
;
}
.field
{
margin-bottom
:
16px
;
}
label
{
display
:
block
;
font-size
:
13px
;
font-weight
:
600
;
margin-bottom
:
6px
;
}
input
{
width
:
100%
;
height
:
44px
;
padding
:
0
14px
;
font-size
:
15px
;
font-family
:
inherit
;
border
:
1px
solid
var
(
--color-border
);
border-radius
:
8px
;
outline
:
none
;
}
input
:focus
{
border-color
:
var
(
--color-primary
);
box-shadow
:
0
0
0
3px
rgba
(
30
,
64
,
175
,
0.12
);
}
button
{
width
:
100%
;
height
:
46px
;
margin-top
:
8px
;
background
:
var
(
--color-primary
);
color
:
#fff
;
font-family
:
inherit
;
font-size
:
15px
;
font-weight
:
600
;
border
:
none
;
border-radius
:
8px
;
cursor
:
pointer
;
}
button
:hover
{
background
:
var
(
--color-primary-hover
);
}
.alert
{
padding
:
12px
14px
;
border-radius
:
8px
;
font-size
:
13.5px
;
margin-bottom
:
16px
;
border
:
1px
solid
;
}
.alert-error
{
background
:
var
(
--color-danger-bg
);
border-color
:
var
(
--color-danger-border
);
color
:
#7F1D1D
;
}
.alert-success
{
background
:
var
(
--color-success-bg
);
border-color
:
var
(
--color-success-border
);
color
:
#14532D
;
}
</style>
</head>
<body>
<div
class=
"page"
>
<div
class=
"nav"
>
<a
href=
"/admin/transactions"
>
«
Lịch sử giao dịch
</a>
</div>
<div
class=
"card"
>
<h1>
Đổi mật khẩu
</h1>
{% if success %}
<div
class=
"alert alert-success"
>
Đã đổi mật khẩu thành công.
</div>
{% endif %}
{% if error %}
<div
class=
"alert alert-error"
>
{{error}}
</div>
{% endif %}
<form
method=
"POST"
action=
"/admin/account/password"
id=
"changePasswordForm"
>
<div
class=
"field"
>
<label
for=
"currentPassword"
>
Mật khẩu hiện tại
</label>
<input
type=
"password"
id=
"currentPassword"
name=
"currentPassword"
autocomplete=
"current-password"
required
>
</div>
<div
class=
"field"
>
<label
for=
"newPassword"
>
Mật khẩu mới
</label>
<input
type=
"password"
id=
"newPassword"
name=
"newPassword"
autocomplete=
"new-password"
required
>
</div>
<div
class=
"field"
>
<label
for=
"confirmPassword"
>
Nhập lại mật khẩu mới
</label>
<input
type=
"password"
id=
"confirmPassword"
autocomplete=
"new-password"
required
>
</div>
<button
type=
"submit"
>
Đổi mật khẩu
</button>
</form>
</div>
</div>
<script>
document
.
getElementById
(
'changePasswordForm'
).
addEventListener
(
'submit'
,
function
(
e
)
{
var
newPassword
=
document
.
getElementById
(
'newPassword'
).
value
;
var
confirmPassword
=
document
.
getElementById
(
'confirmPassword'
).
value
;
if
(
newPassword
!==
confirmPassword
)
{
e
.
preventDefault
();
alert
(
'Mật khẩu mới nhập lại không khớp.'
);
}
});
</script>
</body>
</html>
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