updates for forgot-password and reset-password of UI

This commit is contained in:
kunw 2016-05-10 18:43:52 +08:00
parent 475ef0a079
commit 8d7bb89e4f
34 changed files with 751 additions and 164 deletions

View File

@ -1,20 +1,111 @@
package ng
import (
"net/http"
"os"
"path/filepath"
"strings"
"github.com/astaxie/beego"
"github.com/beego/i18n"
"github.com/vmware/harbor/dao"
"github.com/vmware/harbor/utils/log"
)
type BaseController struct {
beego.Controller
i18n.Locale
SelfRegistration bool
IsAdmin bool
AuthMode string
}
type langType struct {
Lang string
Name string
}
const (
viewPath = "sections"
prefixNg = "ng"
viewPath = "sections"
prefixNg = "ng"
defaultLang = "en-US"
)
var supportLanguages map[string]langType
// Prepare extracts the language information from request and populate data for rendering templates.
func (b *BaseController) Prepare() {
var lang string
al := b.Ctx.Request.Header.Get("Accept-Language")
if len(al) > 4 {
al = al[:5] // Only compare first 5 letters.
if i18n.IsExist(al) {
lang = al
}
}
if _, exist := supportLanguages[lang]; exist == false { //Check if support the request language.
lang = defaultLang //Set default language if not supported.
}
sessionLang := b.GetSession("lang")
if sessionLang != nil {
b.SetSession("Lang", lang)
lang = sessionLang.(string)
}
curLang := langType{
Lang: lang,
}
restLangs := make([]*langType, 0, len(langTypes)-1)
for _, v := range langTypes {
if lang != v.Lang {
restLangs = append(restLangs, v)
} else {
curLang.Name = v.Name
}
}
// Set language properties.
b.Lang = lang
b.Data["Lang"] = curLang.Lang
b.Data["CurLang"] = curLang.Name
b.Data["RestLangs"] = restLangs
authMode := strings.ToLower(os.Getenv("AUTH_MODE"))
if authMode == "" {
authMode = "db_auth"
}
b.AuthMode = authMode
b.Data["AuthMode"] = b.AuthMode
selfRegistration := strings.ToLower(os.Getenv("SELF_REGISTRATION"))
if selfRegistration == "on" {
b.SelfRegistration = true
}
sessionUserID := b.GetSession("userId")
if sessionUserID != nil {
b.Data["Username"] = b.GetSession("username")
b.Data["UserId"] = sessionUserID.(int)
var err error
b.IsAdmin, err = dao.IsAdminRole(sessionUserID.(int))
if err != nil {
log.Errorf("Error occurred in IsAdminRole:%v", err)
b.CustomAbort(http.StatusInternalServerError, "Internal error.")
}
}
b.Data["IsAdmin"] = b.IsAdmin
b.Data["SelfRegistration"] = b.SelfRegistration
}
func (bc *BaseController) Forward(title, templateName string) {
bc.Layout = filepath.Join(prefixNg, "layout.htm")
bc.TplName = filepath.Join(prefixNg, templateName)
@ -26,3 +117,41 @@ func (bc *BaseController) Forward(title, templateName string) {
bc.LayoutSections["FooterContent"] = filepath.Join(prefixNg, viewPath, "footer-content.htm")
}
var langTypes []*langType
func init() {
//conf/app.conf -> os.Getenv("config_path")
configPath := os.Getenv("CONFIG_PATH")
if len(configPath) != 0 {
log.Infof("Config path: %s", configPath)
beego.AppConfigPath = configPath
if err := beego.ParseConfig(); err != nil {
log.Warningf("Failed to parse config file: %s, error: %v", configPath, err)
}
}
beego.AddFuncMap("i18n", i18n.Tr)
langs := strings.Split(beego.AppConfig.String("lang::types"), "|")
names := strings.Split(beego.AppConfig.String("lang::names"), "|")
supportLanguages = make(map[string]langType)
langTypes = make([]*langType, 0, len(langs))
for i, v := range langs {
t := langType{
Lang: v,
Name: names[i],
}
langTypes = append(langTypes, &t)
supportLanguages[v] = t
}
for _, lang := range langs {
if err := i18n.SetMessage(lang, "static/i18n/"+"locale_"+lang+".ini"); err != nil {
log.Errorf("Fail to set message file: %s", err.Error())
}
}
}

175
controllers/ng/password.go Normal file
View File

@ -0,0 +1,175 @@
package ng
import (
"bytes"
"net/http"
"os"
"regexp"
"text/template"
"github.com/astaxie/beego"
"github.com/vmware/harbor/dao"
"github.com/vmware/harbor/models"
"github.com/vmware/harbor/utils"
"github.com/vmware/harbor/utils/log"
)
type CommonController struct {
BaseController
}
func (cc *CommonController) Render() error {
return nil
}
type messageDetail struct {
Hint string
URL string
UUID string
}
// SendEmail verifies the Email address and contact SMTP server to send reset password Email.
func (cc *CommonController) SendEmail() {
email := cc.GetString("email")
pass, _ := regexp.MatchString(`^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$`, email)
if !pass {
cc.CustomAbort(http.StatusBadRequest, "email_content_illegal")
} else {
queryUser := models.User{Email: email}
exist, err := dao.UserExists(queryUser, "email")
if err != nil {
log.Errorf("Error occurred in UserExists: %v", err)
cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
}
if !exist {
cc.CustomAbort(http.StatusNotFound, "email_does_not_exist")
}
messageTemplate, err := template.ParseFiles("views/ng/reset-password-mail.tpl")
if err != nil {
log.Errorf("Parse email template file failed: %v", err)
cc.CustomAbort(http.StatusInternalServerError, err.Error())
}
message := new(bytes.Buffer)
harborURL := os.Getenv("HARBOR_URL")
if harborURL == "" {
harborURL = "localhost"
}
uuid, err := dao.GenerateRandomString()
if err != nil {
log.Errorf("Error occurred in GenerateRandomString: %v", err)
cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
}
err = messageTemplate.Execute(message, messageDetail{
Hint: cc.Tr("reset_email_hint"),
URL: harborURL,
UUID: uuid,
})
if err != nil {
log.Errorf("Message template error: %v", err)
cc.CustomAbort(http.StatusInternalServerError, "internal_error")
}
config, err := beego.AppConfig.GetSection("mail")
if err != nil {
log.Errorf("Can not load app.conf: %v", err)
cc.CustomAbort(http.StatusInternalServerError, "internal_error")
}
mail := utils.Mail{
From: config["from"],
To: []string{email},
Subject: cc.Tr("reset_email_subject"),
Message: message.String()}
err = mail.SendMail()
if err != nil {
log.Errorf("Send email failed: %v", err)
cc.CustomAbort(http.StatusInternalServerError, "send_email_failed")
}
user := models.User{ResetUUID: uuid, Email: email}
dao.UpdateUserResetUUID(user)
}
}
type ForgotPasswordController struct {
BaseController
}
func (fpc *ForgotPasswordController) Get() {
fpc.Forward("Forgot Password", "forgot-password.htm")
}
// ResetPasswordController handles request to /resetPassword
type ResetPasswordController struct {
BaseController
}
// Get checks if reset_uuid in the reset link is valid and render the result page for user to reset password.
func (rpc *ResetPasswordController) Get() {
resetUUID := rpc.GetString("reset_uuid")
if resetUUID == "" {
log.Error("Reset uuid is blank.")
rpc.Redirect("/", http.StatusFound)
return
}
queryUser := models.User{ResetUUID: resetUUID}
user, err := dao.GetUser(queryUser)
if err != nil {
log.Errorf("Error occurred in GetUser: %v", err)
rpc.CustomAbort(http.StatusInternalServerError, "Internal error.")
}
if user != nil {
rpc.Data["ResetUuid"] = user.ResetUUID
rpc.Forward("Reset Password", "reset-password.htm")
} else {
rpc.Redirect("/", http.StatusFound)
}
}
// ResetPassword handles request from the reset page and reset password
func (cc *CommonController) ResetPassword() {
resetUUID := cc.GetString("reset_uuid")
if resetUUID == "" {
cc.CustomAbort(http.StatusBadRequest, "Reset uuid is blank.")
}
queryUser := models.User{ResetUUID: resetUUID}
user, err := dao.GetUser(queryUser)
if err != nil {
log.Errorf("Error occurred in GetUser: %v", err)
cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
}
if user == nil {
log.Error("User does not exist")
cc.CustomAbort(http.StatusBadRequest, "User does not exist")
}
password := cc.GetString("password")
if password != "" {
user.Password = password
err = dao.ResetUserPassword(*user)
if err != nil {
log.Errorf("Error occurred in ResetUserPassword: %v", err)
cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
}
} else {
cc.CustomAbort(http.StatusBadRequest, "password_is_required")
}
}

View File

@ -14,4 +14,6 @@ func initNgRouters() {
beego.Router("/ng/repository", &ng.RepositoryController{})
beego.Router("/ng/sign_up", &ng.SignUpController{})
beego.Router("/ng/account_setting", &ng.AccountSettingController{})
beego.Router("/ng/forgot_password", &ng.ForgotPasswordController{})
beego.Router("/ng/reset_password", &ng.ResetPasswordController{})
}

View File

@ -55,4 +55,68 @@ nav .container-custom {
.nav-custom .active {
border-bottom: 3px solid #EFEFEF;
}
.dropdown {
float: left;
}
.dropdown .btn-link:hover,
.dropdown .btn-link:visited,
.dropdown .btn-link:link {
display:inline-block;
text-decoration: none;
color: #FFFFFF;
}
.dropdown-menu {
left: 9%;
}
.dropdown-submenu {
position: relative;
}
.dropdown-submenu>.dropdown-menu {
top: 0;
left: 100%;
margin-top: -6px;
margin-left: -1px;
-webkit-border-radius: 0 6px 6px 6px;
-moz-border-radius: 0 6px 6px;
border-radius: 0 6px 6px 6px;
}
.dropdown-submenu:hover>.dropdown-menu {
display: block;
}
.dropdown-submenu>a:after {
display: block;
content: " ";
float: right;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 5px 0 5px 5px;
border-left-color: #ccc;
margin-top: 5px;
margin-right: -10px;
}
.dropdown-submenu:hover>a:after {
border-left-color: #fff;
}
.dropdown-submenu.pull-left {
float: none;
}
.dropdown-submenu.pull-left>.dropdown-menu {
left: -100%;
margin-left: 10px;
-webkit-border-radius: 6px 0 6px 6px;
-moz-border-radius: 6px 0 6px 6px;
border-radius: 6px 0 6px 6px;
}

View File

@ -27,6 +27,7 @@ body {
.thumbnail {
display: inline-block;
border: none;
padding: 2px;
box-shadow: none;
}

View File

@ -92,6 +92,7 @@
restrict: 'E',
templateUrl: '/static/ng/resources/js/components/log/list-log.directive.html',
replace: true,
scope: true,
controller: ListLogController,
controllerAs: 'vm',
bindToController: true

View File

@ -1,22 +1,30 @@
<ul class="nav navbar-nav navbar-left">
<li ng-show="//!vm.isLoggedIn//" class="dropdown">
<ul ng-if="!vm.isLoggedIn" class="nav navbar-nav navbar-left">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
<span class="glyphicon glyphicon-globe"></span>Language<span class="caret"></span>
<span class="glyphicon glyphicon-globe"></span> Language<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a href="#">//vm.isLoggedIn ? 'Logged In' : 'Not Logged In'//</a></li>
<ul class="dropdown-menu" style="left: 0;">
<li><a href="#">English</a></li>
<li><a href="#">中文</a></li>
</ul>
</li>
<li ng-show="//vm.isLoggedIn//" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
<span class="glyphicon glyphicon-user"></span>//vm.username//<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a href="#">//vm.username//</a></li>
<li><a href="/ng/account_setting">Account Setting</a></li>
<li><a href="#">Log Out</a></li>
</ul>
</li>
</ul>
</ul>
<div ng-if="vm.isLoggedIn" class="dropdown">
<a id="dLabel" role="button" data-toggle="dropdown" class="btn btn-link" data-target="#" href="">
<span class="glyphicon glyphicon-user"></span> //vm.username//
</a>
<ul class="dropdown-menu multi-level" role="menu" aria-labelledby="dropdownMenu">
<li><a href="/ng/account_setting"><span class="glyphicon glyphicon-pencil"></span> Account Setting</a></li>
<li class="dropdown-submenu">
<a tabindex="-1" href="#"><span class="glyphicon glyphicon-globe"></span> Languages</a>
<ul class="dropdown-menu">
<li><a href="#">English</a></li>
<li><a href="#">中文</a></li>
</ul>
</li>
<li class="divider"></li>
<li><a href="#"><span class="glyphicon glyphicon-log-out"></span> Log Out</a></li>
</ul>
</div>

View File

@ -5,44 +5,33 @@
angular
.module('harbor.optional.menu')
.directive('optionalMenu', optionalMenu);
OptionalMenuController.$inject = ['$scope'];
function OptionalMenuController($scope, CurrentUserService) {
function OptionalMenuController($scope, $timeout) {
var vm = this;
vm.username = 'abcde';
$scope.$watch('vm.username', function(current) {
if(current) {
vm.username = current;
console.log('vm.username:' + current);
}
});
}
function optionalMenu() {
var directive = {
'restrict': 'E',
'templateUrl': '/static/ng/resources/js/components/optional-menu/optional-menu.directive.html',
'scope': {
'isLoggedIn': '=',
'username': '='
},
'link': link,
'scope': true,
'controller': OptionalMenuController,
'controllerAs': 'vm',
'bindToController': true
};
return directive;
function link(scope, element, attrs, ctrl) {
scope.$watch('vm.isLoggedIn', function(current) {
if(current) {
ctrl.isLoggedIn = current;
console.log('vm.isLoggedIn:' + current);
ctrl.isLoggedIn = false;
scope.$on('currentUser', function(e, val) {
if(val != null) {
ctrl.isLoggedIn = true;
ctrl.username = val.username;
}
scope.$apply();
});
}
}

View File

@ -6,9 +6,9 @@
.module('harbor.project.member')
.directive('addProjectMember', addProjectMember);
AddProjectMemberController.$inject = ['roles', 'AddProjectMemberService'];
AddProjectMemberController.$inject = ['$scope', 'roles', 'AddProjectMemberService'];
function AddProjectMemberController(roles, AddProjectMemberService) {
function AddProjectMemberController($scope, roles, AddProjectMemberService) {
var vm = this;
vm.username = "";
vm.roles = roles();
@ -16,8 +16,8 @@
vm.save = save;
vm.cancel = cancel;
function save() {
AddProjectMemberService(2, vm.optRole, vm.username)
function save() {
AddProjectMemberService(vm.projectId, vm.optRole, vm.username)
.success(addProjectMemberComplete)
.error(addProjectMemberFailed);
vm.username = "";
@ -46,6 +46,7 @@
'restrict': 'E',
'templateUrl': '/static/ng/resources/js/components/project-member/add-project-member.directive.html',
'scope': {
'projectId': '@',
'isOpen': '=',
'reload': '&'
},

View File

@ -11,7 +11,7 @@
<button ng-if="vm.isOpen" class="btn btn-default" disabled="disabled" type="button"><span class="glyphicon glyphicon-plus"></span>Add Member</button>
</div>
<div class="pane">
<add-project-member ng-show="vm.isOpen" is-open="vm.isOpen" reload='vm.search({projectId: vm.projectId, username: vm.username})'></add-project-member>
<add-project-member ng-show="vm.isOpen" is-open="vm.isOpen" project-id="//vm.projectId//" reload='vm.search({projectId: vm.projectId, username: vm.username})'></add-project-member>
<div class="sub-pane">
<table class="table table-pane" >
<thead>

View File

@ -6,10 +6,17 @@
.module('harbor.project.member')
.directive('listProjectMember', listProjectMember);
ListProjectMemberController.$inject = ['$scope', 'CurrentUserService', 'ListProjectMemberService', '$routeParams'];
ListProjectMemberController.$inject = ['$scope', 'ListProjectMemberService', '$routeParams'];
function ListProjectMemberController($scope, CurrentUserService, ListProjectMemberService, $routeParams) {
function ListProjectMemberController($scope, ListProjectMemberService, $routeParams) {
var vm = this;
vm.currentUser = {};
$scope.$on('currentUser', function(e, val) {
vm.currentUser = val;
console.log('In list-project-member received current user:' + vm.currentUser);
$scope.$apply();
});
vm.isOpen = false;
@ -19,7 +26,8 @@
vm.projectId = $routeParams.project_id;
vm.username = "";
vm.currentUser = {};
vm.retrieve();
function search(e) {
@ -36,34 +44,21 @@
vm.isOpen = true;
}
}
function retrieve() {
$.when(
CurrentUserService()
.success(getCurrentUserSuccess)
.error(getCurrentUserFailed))
.then(function(){
ListProjectMemberService(vm.projectId, {'username': vm.username})
.then(getProjectMemberComplete)
.catch(getProjectMemberFailed);
});
ListProjectMemberService(vm.projectId, {'username': vm.username})
.then(getProjectMemberComplete)
.catch(getProjectMemberFailed);
}
function getCurrentUserSuccess(data, status) {
vm.currentUser = data;
}
function getCurrentUserFailed(e) {
console.log('Failed in getCurrentUser:' + e);
}
function getProjectMemberComplete(response) {
vm.projectMembers = response.data;
}
function getProjectMemberFailed(response) {
console.log('Failed get project members:' + response);
}
}
@ -73,6 +68,7 @@
restrict: 'E',
templateUrl: '/static/ng/resources/js/components/project-member/list-project-member.directive.html',
replace: true,
scope: true,
link: link,
controller: ListProjectMemberController,
controllerAs: 'vm',

View File

@ -38,6 +38,7 @@
var directive = {
'restrict': 'E',
'templateUrl': '/static/ng/resources/js/components/sign-in/sign-in.directive.html',
'scope': true,
'controller': SignInController,
'controllerAs': 'vm',
'bindToController': true

View File

@ -25,9 +25,6 @@
}
}
}
})();

View File

@ -4,10 +4,13 @@
.module('harbor.app', [
'ngRoute',
'ngMessages',
'harbor.session',
'harbor.layout.header',
'harbor.layout.navigation',
'harbor.layout.sign.up',
'harbor.layout.account.setting',
'harbor.layout.forgot.password',
'harbor.layout.reset.password',
'harbor.layout.index',
'harbor.layout.project',
'harbor.layout.repository',
@ -18,7 +21,6 @@
'harbor.services.user',
'harbor.services.repository',
'harbor.services.project.member',
'harbor.session',
'harbor.optional.menu',
'harbor.sign.in',
'harbor.search',

View File

@ -6,9 +6,9 @@
.module('harbor.layout.account.setting')
.controller('AccountSettingController', AccountSettingController);
AccountSettingController.$inject = ['CurrentUserService', 'ChangePasswordService', '$window'];
AccountSettingController.$inject = ['ChangePasswordService', '$scope', '$window'];
function AccountSettingController(CurrentUserService, ChangePasswordService, $window) {
function AccountSettingController(ChangePasswordService, $scope, $window) {
var vm = this;
vm.isOpen = false;
vm.user = {};
@ -18,9 +18,9 @@
vm.changePassword= changePassword;
vm.cancel = cancel;
CurrentUserService()
.success(getCurrentUserSuccess)
.error(getCurrentUserFailed);
$scope.$on('currentUser', function(e, val) {
vm.user = val;
});
function toggleChangePassword() {
if(vm.isOpen) {
@ -30,12 +30,7 @@
}
console.log('vm.isOpen:' + vm.isOpen);
}
function getCurrentUserSuccess(data, status) {
vm.user = angular.copy(data);
console.log(data);
}
function getCurrentUserFailed(data) {
console.log('Failed get current user:' + data);
}

View File

@ -0,0 +1,36 @@
(function() {
'use strict';
angular
.module('harbor.layout.forgot.password')
.controller('ForgotPasswordController', ForgotPasswordController);
ForgotPasswordController.$inject = ['SendMailService'];
function ForgotPasswordController(SendMailService) {
var vm = this;
vm.hasError = false;
vm.errorMessage = '';
vm.sendMail = sendMail;
function sendMail(user) {
vm.hasError = false;
console.log('Email address:' + user.email);
SendMailService(user.email)
.success(sendMailSuccess)
.error(sendMailFailed);
}
function sendMailSuccess(data, status) {
console.log('Successful send mail:' + data);
}
function sendMailFailed(data) {
vm.hasError = true;
vm.errorMessage = data;
console.log('Failed send mail:' + data);
}
}
})();

View File

@ -0,0 +1,10 @@
(function() {
'use strict';
angular
.module('harbor.layout.forgot.password', [
'harbor.services.user'
]);
})();

View File

@ -6,27 +6,10 @@
.module('harbor.layout.header')
.controller('HeaderController', HeaderController);
HeaderController.$inject = ['CurrentUserService', '$scope'];
HeaderController.$inject = ['$scope'];
function HeaderController(CurrentUserService, $scope) {
function HeaderController($scope) {
var vm = this;
vm.isLoggedIn = true;
vm.currentUser = {};
CurrentUserService()
.then(currentUserSucess)
.catch(currentUserFailed);
function currentUserSucess(response) {
vm.isLoggedIn = true;
vm.currentUser.username = response.data.username;
console.log('vm.currentUser.username:' + vm.currentUser.username);
}
function currentUserFailed(e) {
// vm.isLoggedIn = false;
}
}
})();

View File

@ -18,7 +18,7 @@
restrict: 'E',
templateUrl: '/static/ng/resources/js/layout/navigation/navigation-header.directive.html',
link: link,
replace: true,
scope: true,
controller: NavigationHeaderController,
controllerAs: 'vm',
bindToController: true

View File

@ -23,16 +23,15 @@
vm.retrieve();
function retrieve() {
$.when(
CurrentUserService()
.success(getCurrentUserSuccess)
.error(getCurrentUserFailed))
.then(function(){
ListProjectService(vm.projectName, vm.publicity)
.success(listProjectSuccess)
.error(listProjectFailed);
function retrieve() {
$scope.$on('currentUser', function(e, val) {
vm.currentUser = val;
});
ListProjectService(vm.projectName, vm.publicity)
.success(listProjectSuccess)
.error(listProjectFailed);
}
function listProjectSuccess(data, status) {
@ -42,15 +41,7 @@
function listProjectFailed(e) {
console.log('Failed to list Project:' + e);
}
function getCurrentUserSuccess(data, status) {
vm.currentUser = data;
}
function getCurrentUserFailed(e) {
console.log('Failed in getCurrentUser:' + e);
}
$scope.$on('addedSuccess', function(e, val) {
vm.retrieve();
});

View File

@ -0,0 +1,44 @@
(function() {
'use strict';
angular
.module('harbor.layout.reset.password')
.controller('ResetPasswordController', ResetPasswordController);
ResetPasswordController.$inject = ['$location', 'ResetPasswordService'];
function getParameterByName(name, url) {
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
function ResetPasswordController($location, ResetPasswordService) {
var vm = this;
vm.resetUuid = getParameterByName('reset_uuid', $location.absUrl());
vm.resetPassword = resetPassword;
console.log(vm.resetUuid);
function resetPassword(user) {
console.log('rececived password:' + user.password + ', reset_uuid:' + vm.resetUuid);
ResetPasswordService(vm.resetUuid, user.password)
.success(resetPasswordSuccess)
.error(resetPasswordFailed);
}
function resetPasswordSuccess(data, status) {
console.log('Successful reset password:' + data);
}
function resetPasswordFailed(data) {
console.log('Failed reset password:' + data);
}
}
})();

View File

@ -0,0 +1,10 @@
(function() {
'use strict';
angular
.module('harbor.layout.reset.password', [
'harbor.services.user'
]);
})();

View File

@ -1,21 +0,0 @@
(function() {
'use strict';
angular
.module('harbor.services.user')
.factory('ForgotPasswordService', ForgotPasswordService);
ForgotPasswordService.$inject = ['$http', '$log'];
function ForgotPasswordService($http, $log) {
return ForgotPassword;
function ForgotPassword(user) {
}
}
})();

View File

@ -0,0 +1,29 @@
(function() {
'use strict';
angular
.module('harbor.services.user')
.factory('ResetPasswordService', ResetPasswordService);
ResetPasswordService.$inject = ['$http', '$log'];
function ResetPasswordService($http, $log) {
return resetPassword;
function resetPassword(uuid, password) {
return $http({
method: 'POST',
url: '/reset',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
transformRequest: function(obj) {
var str = [];
for(var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
},
data: {'reset_uuid': uuid, 'password': password}
});
}
}
})();

View File

@ -0,0 +1,26 @@
(function() {
'use strict';
angular
.module('harbor.services.user')
.factory('SendMailService', SendMailService);
SendMailService.$inject = ['$http', '$log'];
function SendMailService($http, $log) {
return SendMail;
function SendMail(email) {
return $http
.get('/ng/sendEmail', {
'params': {
'email': email
}
});
}
}
})();

View File

@ -5,34 +5,30 @@
angular
.module('harbor.session')
.controller('CurrentUserController', CurrentUserController)
.directive('currentUser', currentUser);
CurrentUserController.$inject = ['CurrentUserService', '$scope', '$timeout', '$window'];
CurrentUserController.$inject = ['CurrentUserService', '$log', '$window'];
function CurrentUserController(CurrentUserService, $log, $window) {
function CurrentUserController(CurrentUserService, $scope, $timeout, $window) {
var vm = this;
CurrentUserService()
.then(getCurrentUserComplete)
.catch(getCurrentUserFailed);
function getCurrentUserComplete(data) {
$log.info('login success');
function getCurrentUserComplete(response) {
console.log('Successful logged in.');
$timeout(function(){
$scope.$broadcast('currentUser', response.data);
}, 50);
}
function getCurrentUserFailed(e){
if(e.status == 401) {
$window.location = '/ng';
}
console.log('Have not logged in yet.');
$timeout(function(){
$scope.$broadcast('currentUser', null);
});
}
}
function currentUser() {
var directive = {
restrict: 'A',
controller: CurrentUserController,
bindToController: true
}
return directive;
}
})();

View File

@ -13,4 +13,10 @@ func initNgRouters() {
beego.Router("/ng/repository", &ng.RepositoryController{})
beego.Router("/ng/sign_up", &ng.SignUpController{})
beego.Router("/ng/account_setting", &ng.AccountSettingController{})
beego.Router("/ng/forgot_password", &ng.ForgotPasswordController{})
beego.Router("/ng/reset_password", &ng.ResetPasswordController{})
beego.Router("/ng/reset", &ng.CommonController{}, "post:ResetPassword")
beego.Router("/ng/sendEmail", &ng.CommonController{}, "get:SendEmail")
}

View File

@ -1,4 +1,4 @@
<div class="container-fluid container-fluid-custom" current-user>
<div class="container-fluid container-fluid-custom">
<div class="container">
<div class="row row-custom">
<div class="col-xs-4 col-md-4">

View File

@ -0,0 +1,38 @@
<div class="container-fluid container-fluid-custom" ng-controller="ForgotPasswordController as vm">
<div class="container container-custom">
<div class="row extend-height">
<div class="section">
<h1 class="col-md-12 col-md-offset-2 main-title title-color">Forgot Password</h1>
<div class="row">
<div class="col-md-12 col-md-offset-2 main-content">
<form name="form" class="form-horizontal" ng-submit="form.$valid && vm.sendMail(user)" >
<div class="form-group">
<label for="email" class="col-sm-3 control-label">Email:</label>
<div class="col-sm-7">
<input type="email" class="form-control" id="email" ng-model="user.email" ng-model-options="{ updateOn: 'blur' }" name="uEmail" required >
<p class="help-block small-size-fonts">Please input the Email used when you signed up, a reset password Email will be sent to you.</p>
</div>
<div class="col-sm-2">
<span class="asterisk">*</span>
</div>
</div>
<div class="error-message">
<div ng-messages="form.uEmail.$error">
<span ng-message="required">Email is required.</span>
</div>
<div ng-show="vm.hasError">
<span>//vm.errorMessage//</span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-8 col-md-10">
<input type="submit" class="btn btn-success" value="Send">
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -4,7 +4,7 @@
<title>{{.Title}}</title>
</head>
<body ng-app="harbor.app">
<body ng-app="harbor.app" ng-controller="CurrentUserController as vm">
{{.HeaderContent}}
{{.LayoutContent}}
{{.FooterContent}}

View File

@ -0,0 +1,21 @@
<!--
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!DOCTYPE html>
<html>
<body>
<p>{{.Hint}}:</p>
<a href="{{.URL}}/ng/reset_password?reset_uuid={{.UUID}}">{{.URL}}/ng/reset_password?reset_uuid={{.UUID}}</a>
</body>
</html>

View File

@ -0,0 +1,48 @@
<div class="container-fluid container-fluid-custom" ng-controller="ResetPasswordController as vm">
<div class="container container-custom">
<div class="row extend-height">
<div class="section">
<h1 class="col-md-12 col-md-offset-2 main-title title-color">Reset Password</h1>
<div class="row">
<div class="col-md-12 col-md-offset-2 main-content">
<form name="form" class="form-horizontal css-form" ng-submit="form.$valid && vm.resetPassword(user)" novalidate>
<div class="form-group">
<label for="password" class="col-sm-3 control-label">Password:</label>
<div class="col-sm-7">
<input type="password" class="form-control" id="password" ng-model="user.password" ng-model-options="{ updateOn: 'blur' }" name="uPassword" required password>
<p class="help-block small-size-fonts">At least 7 characters with 1 lowercase letter, 1 capital letter and 1 numeric character.</p>
</div>
<div class="col-sm-2">
<span class="asterisk">*</span>
</div>
</div>
<div class="form-group">
<label for="confirmPassword" class="col-sm-3 control-label">Confirm Password:</label>
<div class="col-sm-7">
<input type="password" class="form-control" id="confirmPassword" ng-model="user.confirmPassword" ng-model-options="{ updateOn: 'blur' }" name="uConfirmPassword" compare-to="user.password">
</div>
<div class="col-sm-2">
<span class="asterisk">*</span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-7 col-md-10">
<input type="submit" class="btn btn-default" ng-click="vm.cancel()" value="Cancel">
<input type="submit" class="btn btn-primary" ng-disabled="form.$invalid" value="Save">
</div>
</div>
<div class="error-message">
<div ng-messages="form.$dirty && form.uPassword.$error">
<span ng-message="required">New password is required.</span>
<span ng-message="password">New password is invalid.</span>
</div>
<div class="error-message" ng-messages="form.$dirty && form.uConfirmPassword.$error">
<span ng-message="compareTo">Confirm password mismatch.</span>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,4 +1,4 @@
<nav class="navbar navbar-default navbar-custom" >
<nav class="navbar navbar-default navbar-custom" ng-controller="HeaderController as vm">
<div class="container container-custom">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
@ -9,8 +9,8 @@
<a class="navbar-brand" href="#"><img class="img-responsive" src="/static/ng/resources/img/Harbor_Logo_rec.png" alt="Harbor's Logo"/></a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-harbor-navbar-collapse-1" ng-controller="HeaderController as vm">
<optional-menu is-logged-in="vm.isLoggedIn" username="vm.currentUser.username"></optional-menu>
<div class="collapse navbar-collapse" id="bs-harbor-navbar-collapse-1">
<optional-menu></optional-menu>
<ul class="nav navbar-nav navbar-right">
<li>
<navigation-header></navigation-header>

View File

@ -54,6 +54,12 @@
<script src="/static/ng/resources/js/layout/account-setting/account-setting.module.js"></script>
<script src="/static/ng/resources/js/layout/account-setting/account-setting.controller.js"></script>
<script src="/static/ng/resources/js/layout/forgot-password/forgot-password.module.js"></script>
<script src="/static/ng/resources/js/layout/forgot-password/forgot-password.controller.js"></script>
<script src="/static/ng/resources/js/layout/reset-password/reset-password.module.js"></script>
<script src="/static/ng/resources/js/layout/reset-password/reset-password.controller.js"></script>
<script src="/static/ng/resources/js/layout/index/index.module.js"></script>
<script src="/static/ng/resources/js/layout/index/index.controller.js"></script>
@ -90,6 +96,9 @@
<script src="/static/ng/resources/js/services/user/services.sign-up.js"></script>
<script src="/static/ng/resources/js/services/user/services.user-exist.js"></script>
<script src="/static/ng/resources/js/services/user/services.change-password.js"></script>
<script src="/static/ng/resources/js/services/user/services.send-mail.js"></script>
<script src="/static/ng/resources/js/services/user/services.reset-password.js"></script>
<script src="/static/ng/resources/js/services/repository/services.repository.module.js"></script>
<script src="/static/ng/resources/js/services/repository/services.list-repository.js"></script>