diff --git a/.gitignore b/.gitignore index 13f454021..db3b37678 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,14 @@ harbor -Deploy/config/registry/config.yml -Deploy/config/ui/env -Deploy/config/ui/app.conf -Deploy/config/db/env -Deploy/config/jobservice/env -Deploy/config/nginx/nginx.conf -Deploy/config/nginx/cert/* -Deploy/ui/harbor_ui -Deploy/jobservice/harbor_jobservice -ui/ui +make/common/config/registry/config.yml +make/common/config/ui/env +make/common/config/ui/app.conf +make/common/config/db/env +make/common/config/jobservice/env +make/common/config/nginx/nginx.conf +make/common/config/nginx/cert/* +make/dev/ui/harbor_ui +make/dev//jobservice/harbor_jobservice +src/ui/ui +src/jobservice/jobservice *.pyc jobservice/test diff --git a/Makefile b/Makefile index 66195ba66..52b5ffefa 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,6 @@ # for example: make package_online -e \ # REGISTRYSERVER=reg-bj.eng.vmware.com \ # REGISTRYPROJECTNAME=harborrelease -# note**: DONT add "/" on end of REGISTRYSERVER. # # package_offline: # prepare offline install package @@ -62,6 +61,9 @@ # note**: If commit new code to github, the git commit TAG will \ # change. Better use this commond clean previous images and \ # files with specific TAG. +# By default DEVFLAG=true, if you want to release new version of Harbor, \ +# should setting the flag to false. +# make XXXX -e DEVFLAG=flase SHELL := /bin/bash BUILDPATH=$(CURDIR) @@ -75,6 +77,7 @@ BASEIMAGE=photon COMPILETAG=compile_normal REGISTRYSERVER= REGISTRYPROJECTNAME=vmware +DEVFLAG=true # docker parameters DOCKERCMD=$(shell which docker) @@ -96,11 +99,13 @@ GODEP=$(GOTEST) -i GOFMT=gofmt -w GOBUILDIMAGE=reg.mydomain.com/library/harborgo[:tag] GOBUILDPATH=$(GOBASEPATH)/harbor -GOBUILDPATH_UI=$(GOBUILDPATH)/ui -GOBUILDPATH_JOBSERVICE=$(GOBUILDPATH)/jobservice +GOIMAGEBUILDCMD=/usr/local/go/bin/go +GOIMAGEBUILD=$(GOIMAGEBUILDCMD) build +GOBUILDPATH_UI=$(GOBUILDPATH)/src/ui +GOBUILDPATH_JOBSERVICE=$(GOBUILDPATH)/src/jobservice GOBUILDMAKEPATH=$(GOBUILDPATH)/make -GOBUILDMAKEPATH_UI=$(GOBUILDMAKEPATH)/ui -GOBUILDMAKEPATH_JOBSERVICE=$(GOBUILDMAKEPATH)/jobservice +GOBUILDMAKEPATH_UI=$(GOBUILDMAKEPATH)/dev/ui +GOBUILDMAKEPATH_JOBSERVICE=$(GOBUILDMAKEPATH)/dev/jobservice # binary UISOURCECODE=$(SRCPATH)/ui @@ -128,10 +133,10 @@ DOCKERFILEPATH_DB=$(DOCKERFILEPATH_COMMON)/db DOCKERFILENAME_DB=Dockerfile # docker image name -DOCKERIMAGENAME_UI=$(REGISTRYPROJECTNAME)/harbor-ui -DOCKERIMAGENAME_JOBSERVICE=$(REGISTRYPROJECTNAME)/harbor-jobservice -DOCKERIMAGENAME_LOG=$(REGISTRYPROJECTNAME)/harbor-log -DOCKERIMAGENAME_DB=$(REGISTRYPROJECTNAME)/harbor-db +DOCKERIMAGENAME_UI=vmware/harbor-ui +DOCKERIMAGENAME_JOBSERVICE=vmware/harbor-jobservice +DOCKERIMAGENAME_LOG=vmware/harbor-log +DOCKERIMAGENAME_DB=vmware/harbor-db # docker-compose files @@ -143,7 +148,12 @@ VERSIONFILEPATH=$(SRCPATH)/ui/views/sections VERSIONFILENAME=header-content.htm GITCMD=$(shell which git) GITTAG=$(GITCMD) describe --tags -VERSIONTAG=$(shell $(GITTAG)) +ifeq ($(DEVFLAG), true) + VERSIONTAG=dev +else + VERSIONTAG=$(shell $(GITTAG)) +endif + SEDCMD=$(shell which sed) # package @@ -186,11 +196,11 @@ compile_golangimage: @echo "compiling binary for ui (golang image)..." @echo $(GOBASEPATH) @echo $(GOBUILDPATH) - $(DOCKERCMD) run --rm -v $(BUILDPATH):$(GOBUILDPATH) -w $(GOBUILDPATH_UI) $(GOBUILDIMAGE) $(GOBUILD) -v -o $(GOBUILDMAKEPATH_UI)/$(UIBINARYNAME) + $(DOCKERCMD) run --rm -v $(BUILDPATH):$(GOBUILDPATH) -w $(GOBUILDPATH_UI) $(GOBUILDIMAGE) $(GOIMAGEBUILD) -v -o $(GOBUILDMAKEPATH_UI)/$(UIBINARYNAME) @echo "Done." @echo "compiling binary for jobservice (golang image)..." - $(DOCKERCMD) run --rm -v $(BUILDPATH):$(GOBUILDPATH) -w $(GOBUILDPATH_JOBSERVICE) $(GOBUILDIMAGE) $(GOBUILD) -v -o $(GOBUILDMAKEPATH_JOBSERVICE)/$(JOBSERVICEBINARYNAME) + $(DOCKERCMD) run --rm -v $(BUILDPATH):$(GOBUILDPATH) -w $(GOBUILDPATH_JOBSERVICE) $(GOBUILDIMAGE) $(GOIMAGEBUILD) -v -o $(GOBUILDMAKEPATH_JOBSERVICE)/$(JOBSERVICEBINARYNAME) @echo "Done." compile:check_environment $(COMPILETAG) @@ -209,10 +219,10 @@ build_common: prepare version $(DOCKERPULL) nginx:1.9 build_photon: build_common - make -f $(MAKEFILEPATH_PHOTON)/Makefile build + make -f $(MAKEFILEPATH_PHOTON)/Makefile build -e DEVFLAG=$(DEVFLAG) build_ubuntu: build_common - make -f $(MAKEFILEPATH_UBUNTU)/Makefile build + make -f $(MAKEFILEPATH_UBUNTU)/Makefile build -e DEVFLAG=$(DEVFLAG) build: build_$(BASEIMAGE) @@ -230,8 +240,10 @@ install: compile build modify_composefile package_online: modify_composefile @echo "packing online package ..." @cp -r make $(HARBORPKG) - @$(SEDCMD) -i 's/image\: vmware/image\: $(REGISTRYSERVER)\/$(REGISTRYPROJECTNAME)/' $(HARBORPKG)/docker-compose.$(VERSIONTAG).yml - + @if [ -n "$(REGISTRYSERVER)" ] ; then \ + $(SEDCMD) -i 's/image\: vmware/image\: $(REGISTRYSERVER)\/$(REGISTRYPROJECTNAME)/' \ + $(HARBORPKG)/docker-compose.$(VERSIONTAG).yml ; \ + fi @cp LICENSE $(HARBORPKG)/LICENSE @cp NOTICE $(HARBORPKG)/NOTICE @$(TARCMD) -zcvf harbor-online-installer-$(VERSIONTAG).tgz \ @@ -258,7 +270,7 @@ package_offline: compile build modify_composefile $(DOCKERIMAGENAME_LOG):$(VERSIONTAG) \ $(DOCKERIMAGENAME_DB):$(VERSIONTAG) \ $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) \ - nginx:1.9.0 registry:2.5.0 + nginx:1.9 registry:2.5.0 @$(TARCMD) -zcvf harbor-offline-installer-$(VERSIONTAG).tgz \ --exclude=$(HARBORPKG)/common/db --exclude=$(HARBORPKG)/ubuntu \ @@ -274,10 +286,10 @@ package_offline: compile build modify_composefile pushimage: @echo "pushing harbor images ..." - @$(DOCKERTAG) $(DOCKERIMAGENAME_UI):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_UI):$(VERSIONTAG) - @$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_UI):$(VERSIONTAG) \ + $(DOCKERTAG) $(DOCKERIMAGENAME_UI):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_UI):$(VERSIONTAG) + $(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_UI):$(VERSIONTAG) \ $(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER) - @$(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKERIMAGENAME_UI):$(VERSIONTAG) + $(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKERIMAGENAME_UI):$(VERSIONTAG) @$(DOCKERTAG) $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) @$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) \ @@ -315,8 +327,8 @@ cleanimage: - $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_DB):$(VERSIONTAG) - $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) - $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_LOG):$(VERSIONTAG) - - $(DOCKERRMIMAGE) -f registry:2.5.0 - - $(DOCKERRMIMAGE) -f nginx:1.9 + #- $(DOCKERRMIMAGE) -f registry:2.5.0 + #- $(DOCKERRMIMAGE) -f nginx:1.9 cleandockercomposefile: @echo "cleaning $(DOCKERCOMPOSEFILEPATH)/docker-compose.$(VERSIONTAG).yml" @@ -333,9 +345,17 @@ cleanpackage: then rm $(BUILDPATH)/harbor-online-installer-$(VERSIONTAG).tgz ; fi @if [ -f $(BUILDPATH)/harbor-offline-installer-$(VERSIONTAG).tgz ] ; \ then rm $(BUILDPATH)/harbor-offline-installer-$(VERSIONTAG).tgz ; fi - -.PHONY: clean -clean: cleanbinary cleanimage cleandockercomposefile cleanversiontag cleanpackage -all: install +.PHONY: cleanall +cleanall: cleanbinary cleanimage cleandockercomposefile cleanversiontag cleanpackage +clean: + @echo " make cleanall: remove binary, Harbor images, specific version docker-compose" + @echo " file, specific version tag, online and offline install package" + @echo " make cleanbinary: remove ui and jobservice binary" + @echo " make cleanimage: remove Harbor images" + @echo " make cleandockercomposefile: remove specific version docker-compose" + @echo " make cleanversiontag: cleanpackageremove specific version tag" + @echo " make cleanpackage: remove online and offline install package" + +all: install \ No newline at end of file diff --git a/make/checkenv.sh b/make/checkenv.sh index 2187c474d..4c82c5522 100755 --- a/make/checkenv.sh +++ b/make/checkenv.sh @@ -69,7 +69,7 @@ function check_golang { fi # docker has been installed and check its version - if [[ $(go version) =~ (([0-9]+).([0-9]+).([0-9]+)) ]] + if [[ $(go version) =~ (([0-9]+)\.([0-9]+)([\.0-9]*)) ]] then golang_version=${BASH_REMATCH[1]} golang_version_part1=${BASH_REMATCH[2]} @@ -97,7 +97,7 @@ function check_docker { fi # docker has been installed and check its version - if [[ $(docker --version) =~ (([0-9]+).([0-9]+).([0-9]+)) ]] + if [[ $(docker --version) =~ (([0-9]+)\.([0-9]+)([\.0-9]*)) ]] then docker_version=${BASH_REMATCH[1]} docker_version_part1=${BASH_REMATCH[2]} @@ -125,7 +125,7 @@ function check_dockercompose { fi # docker-compose has been installed, check its version - if [[ $(docker-compose --version) =~ (([0-9]+).([0-9]+).([0-9]+)) ]] + if [[ $(docker-compose --version) =~ (([0-9]+)\.([0-9]+)([\.0-9]*)) ]] then docker_compose_version=${BASH_REMATCH[1]} docker_compose_version_part1=${BASH_REMATCH[2]} diff --git a/make/dev/jobservice/harbor_jobservice b/make/dev/jobservice/harbor_jobservice deleted file mode 100755 index 918335499..000000000 Binary files a/make/dev/jobservice/harbor_jobservice and /dev/null differ diff --git a/make/dev/ui/harbor_ui b/make/dev/ui/harbor_ui deleted file mode 100755 index 3f90cbb8a..000000000 Binary files a/make/dev/ui/harbor_ui and /dev/null differ diff --git a/make/photon/Makefile b/make/photon/Makefile index ad4bd8487..81fac2acd 100644 --- a/make/photon/Makefile +++ b/make/photon/Makefile @@ -2,17 +2,18 @@ # # Targets: # -# build: build harbor photon images +# build: build harbor ubuntu images # clean: clean ui and jobservice harbor images # common SHELL := /bin/bash BUILDPATH=$(CURDIR) -DEPLOYPATH=$(BUILDPATH)/make -DEPLOYDEVPATH=$(DEPLOYPATH)/dev +MAKEPATH=$(BUILDPATH)/make +MAKEDEVPATH=$(MAKEPATH)/dev SRCPATH=./src TOOLSPATH=$(BUILDPATH)/tools CHECKENVCMD=checkenv.sh +DEVFLAG=true # docker parameters DOCKERCMD=$(shell which docker) @@ -22,14 +23,14 @@ DOCKERIMASES=$(DOCKERCMD) images # binary UISOURCECODE=$(SRCPATH)/ui -UIBINARYPATH=$(DEPLOYDEVPATH)/ui +UIBINARYPATH=$(MAKEDEVPATH)/ui UIBINARYNAME=harbor_ui JOBSERVICESOURCECODE=$(SRCPATH)/jobservice -JOBSERVICEBINARYPATH=$(DEPLOYDEVPATH)/jobservice +JOBSERVICEBINARYPATH=$(MAKEDEVPATH)/jobservice JOBSERVICEBINARYNAME=harbor_jobservice -# photon dockerfile -DOCKERFILEPATH=$(DEPLOYPATH)/photon +# ubuntu dockerfile +DOCKERFILEPATH=$(MAKEPATH)/ubuntu DOCKERFILEPATH_UI=$(DOCKERFILEPATH)/ui DOCKERFILENAME_UI=Dockerfile DOCKERIMAGENAME_UI=vmware/harbor-ui @@ -45,26 +46,30 @@ VERSIONFILEPATH=$(SRCPATH)/views/sections VERSIONFILENAME=header-content.htm GITCMD=$(shell which git) GITTAG=$(GITCMD) describe --tags -VERSIONTAG=$(shell $(GITTAG)) +ifeq ($(DEVFLAG), true) + VERSIONTAG=dev +else + VERSIONTAG=$(shell $(GITTAG)) +endif check_environment: - @$(TOOLSPATH)/$(CHECKENVCMD) + @$(MAKEPATH)/$(CHECKENVCMD) -build: - @echo "building ui container for photon..." +build: + @echo "building ui container for ubuntu..." $(DOCKERBUILD) -f $(DOCKERFILEPATH_UI)/$(DOCKERFILENAME_UI) -t $(DOCKERIMAGENAME_UI):$(VERSIONTAG) . @echo "Done." - @echo "building jobservice container for photon..." + @echo "building jobservice container for ubuntu..." $(DOCKERBUILD) -f $(DOCKERFILEPATH_JOBSERVICE)/$(DOCKERFILENAME_JOBSERVICE) -t $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) . @echo "Done." - @echo "building log container for photon..." + @echo "building log container for ubuntu..." $(DOCKERBUILD) -f $(DOCKERFILEPATH_LOG)/$(DOCKERFILENAME_LOG) -t $(DOCKERIMAGENAME_LOG):$(VERSIONTAG) . @echo "Done." cleanimage: - @echo "cleaning image for photon..." + @echo "cleaning image for ubuntu..." - $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_UI):$(VERSIONTAG) - $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) - $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_LOG):$(VERSIONTAG) diff --git a/make/ubuntu/Makefile b/make/ubuntu/Makefile index 7a8e7a655..81fac2acd 100644 --- a/make/ubuntu/Makefile +++ b/make/ubuntu/Makefile @@ -8,11 +8,12 @@ # common SHELL := /bin/bash BUILDPATH=$(CURDIR) -DEPLOYPATH=$(BUILDPATH)/make -DEPLOYDEVPATH=$(DEPLOYPATH)/dev +MAKEPATH=$(BUILDPATH)/make +MAKEDEVPATH=$(MAKEPATH)/dev SRCPATH=./src TOOLSPATH=$(BUILDPATH)/tools CHECKENVCMD=checkenv.sh +DEVFLAG=true # docker parameters DOCKERCMD=$(shell which docker) @@ -22,14 +23,14 @@ DOCKERIMASES=$(DOCKERCMD) images # binary UISOURCECODE=$(SRCPATH)/ui -UIBINARYPATH=$(DEPLOYDEVPATH)/ui +UIBINARYPATH=$(MAKEDEVPATH)/ui UIBINARYNAME=harbor_ui JOBSERVICESOURCECODE=$(SRCPATH)/jobservice -JOBSERVICEBINARYPATH=$(DEPLOYDEVPATH)/jobservice +JOBSERVICEBINARYPATH=$(MAKEDEVPATH)/jobservice JOBSERVICEBINARYNAME=harbor_jobservice # ubuntu dockerfile -DOCKERFILEPATH=$(DEPLOYPATH)/ubuntu +DOCKERFILEPATH=$(MAKEPATH)/ubuntu DOCKERFILEPATH_UI=$(DOCKERFILEPATH)/ui DOCKERFILENAME_UI=Dockerfile DOCKERIMAGENAME_UI=vmware/harbor-ui @@ -45,12 +46,16 @@ VERSIONFILEPATH=$(SRCPATH)/views/sections VERSIONFILENAME=header-content.htm GITCMD=$(shell which git) GITTAG=$(GITCMD) describe --tags -VERSIONTAG=$(shell $(GITTAG)) +ifeq ($(DEVFLAG), true) + VERSIONTAG=dev +else + VERSIONTAG=$(shell $(GITTAG)) +endif check_environment: - @$(TOOLSPATH)/$(CHECKENVCMD) + @$(MAKEPATH)/$(CHECKENVCMD) -build: +build: @echo "building ui container for ubuntu..." $(DOCKERBUILD) -f $(DOCKERFILEPATH_UI)/$(DOCKERFILENAME_UI) -t $(DOCKERIMAGENAME_UI):$(VERSIONTAG) . @echo "Done." diff --git a/src/common/dao/dao_test.go b/src/common/dao/dao_test.go index ebb03b990..c276f3bf6 100644 --- a/src/common/dao/dao_test.go +++ b/src/common/dao/dao_test.go @@ -428,7 +428,13 @@ func TestResetUserPassword(t *testing.T) { } func TestChangeUserPassword(t *testing.T) { - err := ChangeUserPassword(models.User{UserID: currentUser.UserID, Password: "NewHarborTester12345", Salt: currentUser.Salt}) + user := models.User{UserID: currentUser.UserID} + query, err := GetUser(user) + if err != nil { + t.Errorf("Error occurred when get user salt") + } + currentUser.Salt = query.Salt + err = ChangeUserPassword(models.User{UserID: currentUser.UserID, Password: "NewHarborTester12345", Salt: currentUser.Salt}) if err != nil { t.Errorf("Error occurred in ChangeUserPassword: %v", err) } @@ -444,7 +450,14 @@ func TestChangeUserPassword(t *testing.T) { } func TestChangeUserPasswordWithOldPassword(t *testing.T) { - err := ChangeUserPassword(models.User{UserID: currentUser.UserID, Password: "NewerHarborTester12345", Salt: currentUser.Salt}, "NewHarborTester12345") + user := models.User{UserID: currentUser.UserID} + query, err := GetUser(user) + if err != nil { + t.Errorf("Error occurred when get user salt") + } + currentUser.Salt = query.Salt + + err = ChangeUserPassword(models.User{UserID: currentUser.UserID, Password: "NewerHarborTester12345", Salt: currentUser.Salt}, "NewHarborTester12345") if err != nil { t.Errorf("Error occurred in ChangeUserPassword: %v", err) } diff --git a/src/common/dao/user.go b/src/common/dao/user.go index 49011ada0..765a504db 100644 --- a/src/common/dao/user.go +++ b/src/common/dao/user.go @@ -137,11 +137,12 @@ func ChangeUserPassword(u models.User, oldPassword ...string) (err error) { o := GetOrmer() var r sql.Result + salt := utils.GenerateRandomString() if len(oldPassword) == 0 { //In some cases, it may no need to check old password, just as Linux change password policies. - r, err = o.Raw(`update user set password=?, salt=? where user_id=?`, utils.Encrypt(u.Password, u.Salt), u.Salt, u.UserID).Exec() + r, err = o.Raw(`update user set password=?, salt=? where user_id=?`, utils.Encrypt(u.Password, salt), salt, u.UserID).Exec() } else { - r, err = o.Raw(`update user set password=?, salt=? where user_id=? and password = ?`, utils.Encrypt(u.Password, u.Salt), u.Salt, u.UserID, utils.Encrypt(oldPassword[0], u.Salt)).Exec() + r, err = o.Raw(`update user set password=?, salt=? where user_id=? and password = ?`, utils.Encrypt(u.Password, salt), salt, u.UserID, utils.Encrypt(oldPassword[0], u.Salt)).Exec() } if err != nil { diff --git a/src/common/models/user.go b/src/common/models/user.go index ad93d0e5e..2b46accaa 100644 --- a/src/common/models/user.go +++ b/src/common/models/user.go @@ -35,7 +35,7 @@ type User struct { // RoleList []Role `json:"role_list"` HasAdminRole int `orm:"column(sysadmin_flag)" json:"has_admin_role"` ResetUUID string `orm:"column(reset_uuid)" json:"reset_uuid"` - Salt string `orm:"column(salt)"` + Salt string `orm:"column(salt)" json:"-"` CreationTime time.Time `orm:"creation_time" json:"creation_time"` UpdateTime time.Time `orm:"update_time" json:"update_time"` } diff --git a/src/ui/api/dataprepare_test.go b/src/ui/api/dataprepare_test.go index feb4bbc1f..928c517a1 100644 --- a/src/ui/api/dataprepare_test.go +++ b/src/ui/api/dataprepare_test.go @@ -34,8 +34,8 @@ func CommonAddUser() { commonUser := models.User{ Username: TestUserName, - Email: TestUserPwd, - Password: TestUserEmail, + Password: TestUserPwd, + Email: TestUserEmail, } _, _ = dao.Register(commonUser) diff --git a/src/ui/api/harborapi_test.go b/src/ui/api/harborapi_test.go index a2acecda4..5bfb200fb 100644 --- a/src/ui/api/harborapi_test.go +++ b/src/ui/api/harborapi_test.go @@ -12,8 +12,8 @@ import ( "github.com/vmware/harbor/src/common/dao" "github.com/vmware/harbor/src/common/models" - "github.com/vmware/harbor/tests/apitests/apilib" "github.com/vmware/harbor/src/common/utils" + "github.com/vmware/harbor/tests/apitests/apilib" // "strconv" // "strings" @@ -285,7 +285,7 @@ func (a testapi) ProjectsGetByPID(projectID string) (int, apilib.Project, error) } //Search projects by projectName and isPublic -func (a testapi) ProjectsGet(projectName string, isPublic int32) (int, []apilib.Project, error) { +func (a testapi) ProjectsGet(projectName string, isPublic int32, authInfo ...usrInfo) (int, []apilib.Project, error) { _sling := sling.New().Get(a.basePath) //create api path @@ -299,7 +299,15 @@ func (a testapi) ProjectsGet(projectName string, isPublic int32) (int, []apilib. var successPayload []apilib.Project - httpStatusCode, body, err := request(_sling, jsonAcceptHeader) + var httpStatusCode int + var err error + var body []byte + if len(authInfo) > 0 { + httpStatusCode, body, err = request(_sling, jsonAcceptHeader, authInfo[0]) + } else { + httpStatusCode, body, err = request(_sling, jsonAcceptHeader) + } + if err == nil && httpStatusCode == 200 { err = json.Unmarshal(body, &successPayload) } diff --git a/src/ui/api/log_test.go b/src/ui/api/log_test.go index 593491be0..a7b027a75 100644 --- a/src/ui/api/log_test.go +++ b/src/ui/api/log_test.go @@ -30,8 +30,7 @@ func TestLogGet(t *testing.T) { } logNum := len(result) - logID := result[0].LogId - fmt.Println(result) + fmt.Println("result", result) //add the project first. fmt.Println("add the project first.") reply, err := apiTest.ProjectsPost(*admin, project) @@ -48,12 +47,16 @@ func TestLogGet(t *testing.T) { t.Log(err) } else { assert.Equal(logNum+1, len(result), "lines of logs should be equal") - assert.Equal(int32(logID+1), result[0].LogId, "LogId should be equal") - assert.Equal("my_project/", result[0].RepoName, "RepoName should be equal") - assert.Equal("N/A", result[0].RepoTag, "RepoTag should be equal") - assert.Equal("create", result[0].Operation, "Operation should be equal") + num, index := getLog(result) + if num != 1 { + assert.Equal(1, num, "add my_project log number should be 1") + } else { + assert.Equal("my_project/", result[index].RepoName, "RepoName should be equal") + assert.Equal("N/A", result[index].RepoTag, "RepoTag should be equal") + assert.Equal("create", result[index].Operation, "Operation should be equal") + } } - + fmt.Println("log ", result) //case 2: wrong format of start_time parameter, expect the wrong output now = fmt.Sprintf("%v", time.Now().Unix()) statusCode, result, err = apiTest.LogGet(*admin, "ss", now, "3") @@ -103,13 +106,17 @@ func TestLogGet(t *testing.T) { if logNum+1 >= 10 { logNum = 10 } else { - logNum += 1 + logNum++ } assert.Equal(logNum, len(result), "lines of logs should be equal") - assert.Equal(int32(logID+1), result[0].LogId, "LogId should be equal") - assert.Equal("my_project/", result[0].RepoName, "RepoName should be equal") - assert.Equal("N/A", result[0].RepoTag, "RepoTag should be equal") - assert.Equal("create", result[0].Operation, "Operation should be equal") + num, index := getLog(result) + if num != 1 { + assert.Equal(1, num, "add my_project log number should be 1") + } else { + assert.Equal("my_project/", result[index].RepoName, "RepoName should be equal") + assert.Equal("N/A", result[index].RepoTag, "RepoTag should be equal") + assert.Equal("create", result[index].Operation, "Operation should be equal") + } } //get the project @@ -138,3 +145,14 @@ func TestLogGet(t *testing.T) { fmt.Printf("\n") } + +func getLog(result []apilib.AccessLog) (int, int) { + var num, index int + for i := 0; i < len(result); i++ { + if result[i].RepoName == "my_project/" { + num++ + index = i + } + } + return num, index +} diff --git a/src/ui/api/project.go b/src/ui/api/project.go index c58941ebc..e8828e0e3 100644 --- a/src/ui/api/project.go +++ b/src/ui/api/project.go @@ -286,6 +286,13 @@ func (p *ProjectAPI) List() { if public != 1 { if isAdmin { projectList[i].Role = models.PROJECTADMIN + } else { + roles, err := dao.GetUserProjectRoles(p.userID, projectList[i].ProjectID) + if err != nil { + log.Errorf("failed to get user's project role: %v", err) + p.CustomAbort(http.StatusInternalServerError, "") + } + projectList[i].Role = roles[0].RoleID } if projectList[i].Role == models.PROJECTADMIN { projectList[i].Togglable = true diff --git a/src/ui/api/project_test.go b/src/ui/api/project_test.go index 2b164da6a..8a43d1d3c 100644 --- a/src/ui/api/project_test.go +++ b/src/ui/api/project_test.go @@ -13,7 +13,7 @@ var addProject *apilib.ProjectReq var addPID int func InitAddPro() { - addProject = &apilib.ProjectReq{"test_project", 1} + addProject = &apilib.ProjectReq{"add_project", 1} } func TestAddProject(t *testing.T) { @@ -106,7 +106,49 @@ func TestProGetByName(t *testing.T) { } else { assert.Equal(int(401), httpStatusCode, "httpStatusCode should be 200") } - fmt.Printf("\n") + + //-------------------case 3 : check admin project role------------------------// + httpStatusCode, result, err = apiTest.ProjectsGet(addProject.ProjectName, 0, *admin) + if err != nil { + t.Error("Error while search project by proName and isPublic", err.Error()) + t.Log(err) + } else { + assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200") + assert.Equal(addProject.ProjectName, result[0].ProjectName, "Project name is wrong") + assert.Equal(int32(1), result[0].Public, "Public is wrong") + assert.Equal(int32(1), result[0].CurrentUserRoleId, "User project role is wrong") + } + + //-------------------case 4 : add project member and check his role ------------------------// + CommonAddUser() + roles := &apilib.RoleParam{[]int32{2}, TestUserName} + projectID := strconv.Itoa(addPID) + httpStatusCode, err = apiTest.AddProjectMember(*admin, projectID, *roles) + if err != nil { + t.Error("Error whihle add project role member", err.Error()) + t.Log(err) + } else { + assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200") + } + httpStatusCode, result, err = apiTest.ProjectsGet(addProject.ProjectName, 0, *testUser) + if err != nil { + t.Error("Error while search project by proName and isPublic", err.Error()) + t.Log(err) + } else { + assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200") + assert.Equal(addProject.ProjectName, result[0].ProjectName, "Project name is wrong") + assert.Equal(int32(1), result[0].Public, "Public is wrong") + assert.Equal(int32(2), result[0].CurrentUserRoleId, "User project role is wrong") + } + id := strconv.Itoa(CommonGetUserID()) + httpStatusCode, err = apiTest.DeleteProjectMember(*admin, projectID, id) + if err != nil { + t.Error("Error whihle add project role member", err.Error()) + t.Log(err) + } else { + assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200") + } + CommonDelUser() } //Get project by proID diff --git a/src/ui/api/user.go b/src/ui/api/user.go index d75ba7d3e..7b023b9dc 100644 --- a/src/ui/api/user.go +++ b/src/ui/api/user.go @@ -23,10 +23,10 @@ import ( "strconv" "strings" + "github.com/vmware/harbor/src/common/api" "github.com/vmware/harbor/src/common/dao" "github.com/vmware/harbor/src/common/models" "github.com/vmware/harbor/src/common/utils/log" - "github.com/vmware/harbor/src/common/api" ) // UserAPI handles request to /api/users/{} @@ -152,7 +152,7 @@ func (ua *UserAPI) Put() { ua.DecodeJSONReq(&user) err := commonValidate(user) if err != nil { - log.Warning("Bad request in change user profile: %v", err) + log.Warningf("Bad request in change user profile: %v", err) ua.RenderError(http.StatusBadRequest, "change user profile error:"+err.Error()) return } @@ -200,7 +200,7 @@ func (ua *UserAPI) Post() { ua.DecodeJSONReq(&user) err := validate(user) if err != nil { - log.Warning("Bad request in Register: %v", err) + log.Warningf("Bad request in Register: %v", err) ua.RenderError(http.StatusBadRequest, "register error:"+err.Error()) return } diff --git a/src/ui/api/user_test.go b/src/ui/api/user_test.go index 7ea546990..0e00c78bd 100644 --- a/src/ui/api/user_test.go +++ b/src/ui/api/user_test.go @@ -354,6 +354,16 @@ func TestUsersUpdatePassword(t *testing.T) { assert.Equal(200, code, "Get users status should be 200") testUser0002.Password = password.NewPassword testUser0002Auth.Passwd = password.NewPassword + //TODO: verify the new password takes effect + } + //case 6: update user2 password setting the new password same as the old + password.OldPassword = password.NewPassword + code, err = apiTest.UsersUpdatePassword(testUser0002ID, password, *admin) + if err != nil { + t.Error("Error occured while change user profile", err.Error()) + t.Log(err) + } else { + assert.Equal(200, code, "When new password is same as old, update user password status should be 200") } } diff --git a/src/ui/static/resources/js/components/user/toggle-admin.directive.js b/src/ui/static/resources/js/components/user/toggle-admin.directive.js index c332823f5..b4d3845ab 100644 --- a/src/ui/static/resources/js/components/user/toggle-admin.directive.js +++ b/src/ui/static/resources/js/components/user/toggle-admin.directive.js @@ -26,35 +26,26 @@ var vm = this; vm.isAdmin = (vm.hasAdminRole === 1); - vm.enabled = vm.isAdmin ? 0 : 1; vm.toggle = toggle; vm.editable = (vm.currentUser.user_id !== Number(vm.userId)); function toggle() { - ToggleAdminService(vm.userId, vm.enabled) + ToggleAdminService(vm.userId, vm.isAdmin ? 0 : 1) .success(toggleAdminSuccess) .error(toggleAdminFailed); } - + function toggleAdminSuccess(data, status) { - if(vm.isAdmin) { - vm.isAdmin = false; - }else{ - vm.isAdmin = true; - } console.log('Toggled userId:' + vm.userId + ' to admin:' + vm.isAdmin); + vm.isAdmin = !vm.isAdmin; } function toggleAdminFailed(data, status) { + console.log('Failed to toggle admin:' + data); + vm.isAdmin = !vm.isAdmin; $scope.$emit('modalTitle', $filter('tr')('error')); $scope.$emit('modalMessage', $filter('tr')('failed_to_toggle_admin')); $scope.$emit('raiseError', true); - if(vm.isAdmin) { - vm.isAdmin = false; - }else{ - vm.isAdmin = true; - } - console.log('Failed to toggle admin:' + data); } } diff --git a/src/ui/static/resources/js/components/validator/email.validator.js b/src/ui/static/resources/js/components/validator/email.validator.js new file mode 100644 index 000000000..c7421bfa8 --- /dev/null +++ b/src/ui/static/resources/js/components/validator/email.validator.js @@ -0,0 +1,44 @@ +/* + 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. +*/ +(function() { + + 'use strict'; + + angular + .module('harbor.validator') + .directive('email', email); + + email.$inject = ['EMAIL_REGEXP']; + + function email(EMAIL_REGEXP) { + var directive = { + 'require' : 'ngModel', + 'link': link + }; + return directive; + + function link (scope, element, attrs, ctrl) { + + ctrl.$validators.email = validator; + + function validator(modelValue, viewValue) { + + return EMAIL_REGEXP.test(modelValue); + + } + } + } + +})(); \ No newline at end of file diff --git a/src/ui/static/resources/js/components/validator/validator.config.js b/src/ui/static/resources/js/components/validator/validator.config.js index 187f55008..08e892cdc 100644 --- a/src/ui/static/resources/js/components/validator/validator.config.js +++ b/src/ui/static/resources/js/components/validator/validator.config.js @@ -20,5 +20,7 @@ .module('harbor.validator') .constant('INVALID_CHARS', [",","~","#", "$", "%"]) .constant('PASSWORD_REGEXP', /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{8,20}$/) - .constant('PROJECT_REGEXP', /^[a-z0-9](?:-*[a-z0-9])*(?:[._][a-z0-9](?:-*[a-z0-9])*)*$/); + .constant('PROJECT_REGEXP', /^[a-z0-9](?:-*[a-z0-9])*(?:[._][a-z0-9](?:-*[a-z0-9])*)*$/) + .constant('EMAIL_REGEXP', /^(([^<>()[\]\.,;:\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,}))$/); + })(); \ No newline at end of file diff --git a/src/ui/static/resources/js/session/session.current-user.js b/src/ui/static/resources/js/session/session.current-user.js index 9e51af4cd..a02355c35 100644 --- a/src/ui/static/resources/js/session/session.current-user.js +++ b/src/ui/static/resources/js/session/session.current-user.js @@ -20,9 +20,9 @@ .module('harbor.session') .controller('CurrentUserController', CurrentUserController); - CurrentUserController.$inject = ['$scope', 'CurrentUserService', 'currentUser', '$window', '$document']; + CurrentUserController.$inject = ['$scope', 'CurrentUserService', 'currentUser', '$window', '$document', 'LogOutService']; - function CurrentUserController($scope, CurrentUserService, currentUser, $window, $document) { + function CurrentUserController($scope, CurrentUserService, currentUser, $window, $document, LogOutService) { var vm = this; @@ -32,16 +32,27 @@ function getCurrentUserComplete(response) { if(angular.isDefined(response)) { - currentUser.set(response.data); - if(location.pathname === '/') { + currentUser.set(response.data); + if(location.pathname === '/') { $window.location.href = '/dashboard'; } } } function getCurrentUserFailed(e){ - console.log('No session of current user.'); + console.log('Failed to get current user:' + e); + LogOutService() + .success(logOutSuccess) + .error(logOutFailed); } + + function logOutSuccess(data, status) { + currentUser.unset(); + } + + function logOutFailed(data, status) { + console.log('Failed to log out:' + data); + } } })(); \ No newline at end of file diff --git a/src/ui/views/account-settings.htm b/src/ui/views/account-settings.htm index 7389ca51a..55b7c0d24 100644 --- a/src/ui/views/account-settings.htm +++ b/src/ui/views/account-settings.htm @@ -29,7 +29,7 @@