diff --git a/Deploy/config/nginx/nginx.conf b/Deploy/config/nginx/nginx.conf index 3941e94fa..8168137ea 100644 --- a/Deploy/config/nginx/nginx.conf +++ b/Deploy/config/nginx/nginx.conf @@ -15,12 +15,10 @@ http { upstream registry { server registry:5000; -# check interval=2000 rise=1 fall=1 timeout=5000 type=tcp; } upstream ui { server ui:80; -# check interval=2000 rise=1 fall=1 timeout=5000 type=tcp; } diff --git a/Deploy/docker-compose.yml b/Deploy/docker-compose.yml index f377d8ea5..0c03ae7b3 100644 --- a/Deploy/docker-compose.yml +++ b/Deploy/docker-compose.yml @@ -39,20 +39,20 @@ ui: - ./config/ui/app.conf:/etc/ui/app.conf - ./config/ui/private_key.pem:/etc/ui/private_key.pem links: - - registry:registry - - mysql:mysql + - registry + - mysql - log log_driver: "syslog" log_opt: syslog-address: "tcp://127.0.0.1:1514" syslog-tag: "ui" -roxy: +proxy: image: library/nginx:1.9 volumes: - ./config/nginx/nginx.conf:/etc/nginx/nginx.conf links: - - ui:ui - - registry:registry + - ui + - registry - log ports: - 80:80 diff --git a/Deploy/log/Dockerfile b/Deploy/log/Dockerfile index b7aaa2fc8..246746c6b 100644 --- a/Deploy/log/Dockerfile +++ b/Deploy/log/Dockerfile @@ -1,23 +1,18 @@ FROM library/ubuntu:14.04 -# run logrotate hourly -RUN mv /etc/cron.daily/logrotate /etc/cron.hourly/ +# run logrotate hourly, disable imklog model, provides TCP/UDP syslog reception +RUN mv /etc/cron.daily/logrotate /etc/cron.hourly/ \ + && sed 's/$ModLoad imklog/#$ModLoad imklog/' -i /etc/rsyslog.conf \ + && sed 's/$KLogPermitNonKernelFacility on/#$KLogPermitNonKernelFacility on/' -i /etc/rsyslog.conf \ + && sed 's/#$ModLoad imudp/$ModLoad imudp/' -i /etc/rsyslog.conf \ + && sed 's/#$UDPServerRun 514/$UDPServerRun 514/' -i /etc/rsyslog.conf \ + && sed 's/#$ModLoad imtcp/$ModLoad imtcp/' -i /etc/rsyslog.conf \ + && sed 's/#$InputTCPServerRun 514/$InputTCPServerRun 514/' -i /etc/rsyslog.conf \ + && rm /etc/rsyslog.d/* # logrotate configuration file for docker ADD logrotate_docker.conf /etc/logrotate.d/ -#disable imklog model -RUN sed 's/$ModLoad imklog/#$ModLoad imklog/' -i /etc/rsyslog.conf -RUN sed 's/$KLogPermitNonKernelFacility on/#$KLogPermitNonKernelFacility on/' -i /etc/rsyslog.conf - -# provides TCP/UDP syslog reception -RUN sed 's/#$ModLoad imudp/$ModLoad imudp/' -i /etc/rsyslog.conf -RUN sed 's/#$UDPServerRun 514/$UDPServerRun 514/' -i /etc/rsyslog.conf -RUN sed 's/#$ModLoad imtcp/$ModLoad imtcp/' -i /etc/rsyslog.conf -RUN sed 's/#$InputTCPServerRun 514/$InputTCPServerRun 514/' -i /etc/rsyslog.conf - -RUN rm /etc/rsyslog.d/* - # rsyslog configuration file for docker ADD rsyslog_docker.conf /etc/rsyslog.d/ @@ -26,3 +21,4 @@ VOLUME /var/log/docker/ EXPOSE 514 CMD cron && chown -R syslog:syslog /var/log/docker/ && rsyslogd -n + diff --git a/Dockerfile b/Dockerfile index 468612f62..525c9de88 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,8 +14,8 @@ WORKDIR /go/src/github.com/vmware/harbor ENV GO15VENDOREXPERIMENT 1 RUN go get -d github.com/docker/distribution \ && go get -d github.com/docker/libtrust \ - && go get -d github.com/go-sql-driver/mysql -RUN go install -v -a + && go get -d github.com/go-sql-driver/mysql \ + && go install -v -a ENV MYSQL_USR root \ MYSQL_PWD root \ @@ -23,7 +23,6 @@ ENV MYSQL_USR root \ MYSQL_PORT_3306_TCP_PORT 3306 \ REGISTRY_URL localhost:5000 -COPY conf /go/bin/conf COPY views /go/bin/views COPY static /go/bin/static diff --git a/Dockerfile.offline b/Dockerfile.offline index 4f03681ac..34d56c25f 100644 --- a/Dockerfile.offline +++ b/Dockerfile.offline @@ -9,7 +9,6 @@ ENV REGISTRY_URL localhost:5000 RUN apt-get update -qqy && apt-get install -qqy libldap2-dev ADD harbor /go/bin/harbor -ADD conf /go/bin/conf ADD views /go/bin/views ADD static /go/bin/static diff --git a/api/base.go b/api/base.go index 92578bb78..2262bb3ac 100644 --- a/api/base.go +++ b/api/base.go @@ -40,7 +40,7 @@ func (b *BaseAPI) DecodeJsonReq(v interface{}) { err := json.Unmarshal(b.Ctx.Input.CopyBody(1<<32), v) if err != nil { beego.Error("Error while decoding the json request:", err) - b.CustomAbort(400, "Invalid json request") + b.CustomAbort(http.StatusBadRequest, "Invalid json request") } } @@ -49,17 +49,17 @@ func (b *BaseAPI) ValidateUser() int { sessionUserId := b.GetSession("userId") if sessionUserId == nil { beego.Warning("No user id in session, canceling request") - b.CustomAbort(401, "") + b.CustomAbort(http.StatusUnauthorized, "") } userId := sessionUserId.(int) u, err := dao.GetUser(models.User{UserId: userId}) if err != nil { beego.Error("Error occurred in GetUser:", err) - b.CustomAbort(500, "Internal error.") + b.CustomAbort(http.StatusInternalServerError, "Internal error.") } if u == nil { beego.Warning("User was deleted already, user id: ", userId, " canceling request.") - b.CustomAbort(401, "") + b.CustomAbort(http.StatusUnauthorized, "") } return userId } diff --git a/api/project.go b/api/project.go index 9c711e17d..42944ef51 100644 --- a/api/project.go +++ b/api/project.go @@ -17,6 +17,7 @@ package api import ( "fmt" "log" + "net/http" "github.com/vmware/harbor/dao" "github.com/vmware/harbor/models" @@ -48,15 +49,15 @@ func (p *ProjectAPI) Prepare() { p.projectId, err = strconv.ParseInt(id_str, 10, 64) if err != nil { log.Printf("Error parsing project id: %s, error: %v", id_str, err) - p.CustomAbort(400, "invalid project id") + p.CustomAbort(http.StatusBadRequest, "invalid project id") } exist, err := dao.ProjectExists(p.projectId) if err != nil { log.Printf("Error occurred in ProjectExists: %v", err) - p.CustomAbort(500, "Internal error.") + p.CustomAbort(http.StatusInternalServerError, "Internal error.") } if !exist { - p.CustomAbort(404, fmt.Sprintf("project does not exist, id: %v", p.projectId)) + p.CustomAbort(http.StatusNotFound, fmt.Sprintf("project does not exist, id: %v", p.projectId)) } } } @@ -71,7 +72,7 @@ func (p *ProjectAPI) Post() { err := validateProjectReq(req) if err != nil { beego.Error("Invalid project request, error: ", err) - p.RenderError(400, "Invalid request for creating project") + p.RenderError(http.StatusBadRequest, "Invalid request for creating project") return } projectName := req.ProjectName @@ -80,14 +81,14 @@ func (p *ProjectAPI) Post() { beego.Error("Error happened checking project existence in db:", err, ", project name:", projectName) } if exist { - p.RenderError(409, "") + p.RenderError(http.StatusConflict, "") return } project := models.Project{OwnerId: p.userId, Name: projectName, CreationTime: time.Now(), Public: public} err = dao.AddProject(project) if err != nil { beego.Error("Failed to add project, error: %v", err) - p.RenderError(500, "Failed to add project") + p.RenderError(http.StatusInternalServerError, "Failed to add project") } } @@ -96,11 +97,11 @@ func (p *ProjectAPI) Head() { result, err := dao.ProjectExists(projectName) if err != nil { beego.Error("Error while communicating with DB: ", err) - p.RenderError(500, "Error while communicating with DB") + p.RenderError(http.StatusInternalServerError, "Error while communicating with DB") return } if !result { - p.RenderError(404, "") + p.RenderError(http.StatusNotFound, "") return } } @@ -117,7 +118,7 @@ func (p *ProjectAPI) Get() { projectList, err := dao.QueryProject(queryProject) if err != nil { beego.Error("Error occurred in QueryProject:", err) - p.CustomAbort(500, "Internal error.") + p.CustomAbort(http.StatusInternalServerError, "Internal error.") } for i := 0; i < len(projectList); i++ { if isProjectAdmin(p.userId, projectList[i].ProjectId) { @@ -135,7 +136,7 @@ func (p *ProjectAPI) Put() { projectId, err := strconv.ParseInt(p.Ctx.Input.Param(":id"), 10, 64) if err != nil { beego.Error("Error parsing project id:", projectId, ", error: ", err) - p.RenderError(400, "invalid project id") + p.RenderError(http.StatusBadRequest, "invalid project id") return } @@ -145,13 +146,13 @@ func (p *ProjectAPI) Put() { } if !isProjectAdmin(p.userId, projectId) { beego.Warning("Current user, id:", p.userId, ", does not have project admin role for project, id:", projectId) - p.RenderError(403, "") + p.RenderError(http.StatusForbidden, "") return } err = dao.ToggleProjectPublicity(p.projectId, public) if err != nil { beego.Error("Error while updating project, project id:", projectId, ", error:", err) - p.RenderError(500, "Failed to update project") + p.RenderError(http.StatusInternalServerError, "Failed to update project") } } @@ -162,14 +163,18 @@ func (p *ProjectAPI) FilterAccessLog() { username := filter.Username keywords := filter.Keywords - beginTime := filter.BeginTime - endTime := filter.EndTime - query := models.AccessLog{ProjectId: p.projectId, Username: "%" + username + "%", Keywords: keywords, BeginTime: beginTime, EndTime: endTime} + beginTime := time.Unix(filter.BeginTimestamp, 0) + endTime := time.Unix(filter.EndTimestamp, 0) + + query := models.AccessLog{ProjectId: p.projectId, Username: "%" + username + "%", Keywords: keywords, BeginTime: beginTime, BeginTimestamp: filter.BeginTimestamp, EndTime: endTime, EndTimestamp: filter.EndTimestamp} + + log.Printf("Query AccessLog: begin: %v, end: %v, keywords: %s", query.BeginTime, query.EndTime, query.Keywords) + accessLogList, err := dao.GetAccessLogs(query) if err != nil { log.Printf("Error occurred in GetAccessLogs: %v", err) - p.CustomAbort(500, "Internal error.") + p.CustomAbort(http.StatusInternalServerError, "Internal error.") } p.Data["json"] = accessLogList p.ServeJSON() diff --git a/api/project_member.go b/api/project_member.go index b387958e7..37185ad31 100644 --- a/api/project_member.go +++ b/api/project_member.go @@ -15,12 +15,13 @@ package api import ( + "net/http" + "strconv" + "github.com/vmware/harbor/dao" "github.com/vmware/harbor/models" "github.com/astaxie/beego" - - "strconv" ) type ProjectMemberAPI struct { @@ -40,18 +41,18 @@ func (pma *ProjectMemberAPI) Prepare() { pid, err := strconv.ParseInt(pma.Ctx.Input.Param(":pid"), 10, 64) if err != nil { beego.Error("Error parsing project id:", pid, ", error:", err) - pma.CustomAbort(400, "invalid project Id") + pma.CustomAbort(http.StatusBadRequest, "invalid project Id") return } p, err := dao.GetProjectById(models.Project{ProjectId: pid}) if err != nil { beego.Error("Error occurred in GetProjectById:", err) - pma.CustomAbort(500, "Internal error.") + pma.CustomAbort(http.StatusInternalServerError, "Internal error.") } if p == nil { beego.Warning("Project with id:", pid, "does not exist.") - pma.CustomAbort(404, "Project does not exist") + pma.CustomAbort(http.StatusNotFound, "Project does not exist") } pma.project = p pma.currentUserId = pma.ValidateUser() @@ -64,7 +65,7 @@ func (pma *ProjectMemberAPI) Prepare() { memberId, err := strconv.Atoi(mid) if err != nil { beego.Error("Invalid member Id, error:", err) - pma.CustomAbort(400, "Invalid member id") + pma.CustomAbort(http.StatusBadRequest, "Invalid member id") } pma.memberId = memberId } @@ -74,7 +75,7 @@ func (pma *ProjectMemberAPI) Get() { pid := pma.project.ProjectId if !CheckProjectPermission(pma.currentUserId, pid) { beego.Warning("Current user, user id :", pma.currentUserId, "does not have permission for project, id:", pid) - pma.RenderError(403, "") + pma.RenderError(http.StatusForbidden, "") return } if pma.memberId == 0 { //member id not set return list of the members @@ -84,7 +85,7 @@ func (pma *ProjectMemberAPI) Get() { userList, err := dao.GetUserByProject(queryProject, queryUser) if err != nil { beego.Error("Failed to query database for member list, error:", err) - pma.RenderError(500, "Internal Server Error") + pma.RenderError(http.StatusInternalServerError, "Internal Server Error") return } pma.Data["json"] = userList @@ -92,14 +93,14 @@ func (pma *ProjectMemberAPI) Get() { roleList, err := dao.GetUserProjectRoles(models.User{UserId: pma.memberId}, pid) if err != nil { beego.Error("Error occurred in GetUserProjectRoles:", err) - pma.CustomAbort(500, "Internal error.") + pma.CustomAbort(http.StatusInternalServerError, "Internal error.") } //return empty role list to indicate if a user is not a member result := make(map[string]interface{}) user, err := dao.GetUser(models.User{UserId: pma.memberId}) if err != nil { beego.Error("Error occurred in GetUser:", err) - pma.CustomAbort(500, "Internal error.") + pma.CustomAbort(http.StatusInternalServerError, "Internal error.") } result["user_name"] = user.Username result["user_id"] = pma.memberId @@ -115,11 +116,11 @@ func (pma *ProjectMemberAPI) Post() { rolelist, err := dao.GetUserProjectRoles(userQuery, pid) if err != nil { beego.Error("Error occurred in GetUserProjectRoles:", err) - pma.CustomAbort(500, "Internal error.") + pma.CustomAbort(http.StatusInternalServerError, "Internal error.") } if len(rolelist) == 0 { beego.Warning("Current user, id:", pma.currentUserId, "does not have project admin role for project, id:", pid) - pma.RenderError(403, "") + pma.RenderError(http.StatusForbidden, "") return } var req memberReq @@ -128,17 +129,17 @@ func (pma *ProjectMemberAPI) Post() { userId := CheckUserExists(username) if userId <= 0 { beego.Warning("User does not exist, user name:", username) - pma.RenderError(404, "User does not exist") + pma.RenderError(http.StatusNotFound, "User does not exist") return } rolelist, err = dao.GetUserProjectRoles(models.User{UserId: userId}, pid) if err != nil { beego.Error("Error occurred in GetUserProjectRoles:", err) - pma.CustomAbort(500, "Internal error.") + pma.CustomAbort(http.StatusInternalServerError, "Internal error.") } if len(rolelist) > 0 { beego.Warning("user is already added to project, user id:", userId, ", project id:", pid) - pma.RenderError(409, "user is ready in project") + pma.RenderError(http.StatusConflict, "user is ready in project") return } @@ -146,7 +147,7 @@ func (pma *ProjectMemberAPI) Post() { err = dao.AddUserProjectRole(userId, pid, int(rid)) if err != nil { beego.Error("Failed to update DB to add project user role, project id:", pid, ", user id:", userId, ", role id:", rid) - pma.RenderError(500, "Failed to update data in database") + pma.RenderError(http.StatusInternalServerError, "Failed to update data in database") return } } @@ -159,11 +160,11 @@ func (pma *ProjectMemberAPI) Put() { rolelist, err := dao.GetUserProjectRoles(userQuery, pid) if err != nil { beego.Error("Error occurred in GetUserProjectRoles:", err) - pma.CustomAbort(500, "Internal error.") + pma.CustomAbort(http.StatusInternalServerError, "Internal error.") } if len(rolelist) == 0 { beego.Warning("Current user, id:", pma.currentUserId, ", does not have project admin role for project, id:", pid) - pma.RenderError(403, "") + pma.RenderError(http.StatusForbidden, "") return } var req memberReq @@ -171,7 +172,7 @@ func (pma *ProjectMemberAPI) Put() { roleList, err := dao.GetUserProjectRoles(models.User{UserId: mid}, pid) if len(roleList) == 0 { beego.Warning("User is not in project, user id:", mid, ", project id:", pid) - pma.RenderError(404, "user not exist in project") + pma.RenderError(http.StatusNotFound, "user not exist in project") return } //TODO: delete and insert should in one transaction @@ -179,7 +180,7 @@ func (pma *ProjectMemberAPI) Put() { err = dao.DeleteUserProjectRoles(mid, pid) if err != nil { beego.Error("Failed to delete project roles for user, user id:", mid, ", project id: ", pid, ", error: ", err) - pma.RenderError(500, "Failed to update data in DB") + pma.RenderError(http.StatusInternalServerError, "Failed to update data in DB") return } //insert roles in request @@ -187,7 +188,7 @@ func (pma *ProjectMemberAPI) Put() { err = dao.AddUserProjectRole(mid, pid, int(rid)) if err != nil { beego.Error("Failed to update DB to add project user role, project id:", pid, ", user id:", mid, ", role id:", rid) - pma.RenderError(500, "Failed to update data in database") + pma.RenderError(http.StatusInternalServerError, "Failed to update data in database") return } } @@ -200,13 +201,13 @@ func (pma *ProjectMemberAPI) Delete() { rolelist, err := dao.GetUserProjectRoles(userQuery, pid) if len(rolelist) == 0 { beego.Warning("Current user, id:", pma.currentUserId, ", does not have project admin role for project, id:", pid) - pma.RenderError(403, "") + pma.RenderError(http.StatusForbidden, "") return } err = dao.DeleteUserProjectRoles(mid, pid) if err != nil { beego.Error("Failed to delete project roles for user, user id:", mid, ", project id:", pid, ", error:", err) - pma.RenderError(500, "Failed to update data in DB") + pma.RenderError(http.StatusInternalServerError, "Failed to update data in DB") return } } diff --git a/api/repository.go b/api/repository.go index 284a73515..918724638 100644 --- a/api/repository.go +++ b/api/repository.go @@ -16,6 +16,7 @@ package api import ( "encoding/json" + "net/http" "strconv" "strings" "time" @@ -56,28 +57,28 @@ func (ra *RepositoryAPI) Get() { projectId, err0 := ra.GetInt64("project_id") if err0 != nil { beego.Error("Failed to get project id, error:", err0) - ra.RenderError(400, "Invalid project id") + ra.RenderError(http.StatusBadRequest, "Invalid project id") return } projectQuery := models.Project{ProjectId: projectId} p, err := dao.GetProjectById(projectQuery) if err != nil { beego.Error("Error occurred in GetProjectById:", err) - ra.CustomAbort(500, "Internal error.") + ra.CustomAbort(http.StatusInternalServerError, "Internal error.") } if p == nil { beego.Warning("Project with Id:", projectId, ", does not exist", projectId) - ra.RenderError(404, "") + ra.RenderError(http.StatusNotFound, "") return } if p.Public == 0 && !CheckProjectPermission(ra.userId, projectId) { - ra.RenderError(403, "") + ra.RenderError(http.StatusForbidden, "") return } repoList, err := svc_utils.GetRepoFromCache() if err != nil { beego.Error("Failed to get repo from cache, error:", err) - ra.RenderError(500, "internal sever error") + ra.RenderError(http.StatusInternalServerError, "internal sever error") } projectName := p.Name q := ra.GetString("q") @@ -127,7 +128,7 @@ func (ra *RepositoryAPI) GetTags() { result, err := svc_utils.RegistryApiGet(svc_utils.BuildRegistryUrl(repoName, "tags", "list"), ra.username) if err != nil { beego.Error("Failed to get repo tags, repo name:", repoName, ", error: ", err) - ra.RenderError(500, "Failed to get repo tags") + ra.RenderError(http.StatusInternalServerError, "Failed to get repo tags") } else { t := Tag{} json.Unmarshal(result, &t) @@ -146,14 +147,14 @@ func (ra *RepositoryAPI) GetManifests() { result, err := svc_utils.RegistryApiGet(svc_utils.BuildRegistryUrl(repoName, "manifests", tag), ra.username) if err != nil { beego.Error("Failed to get manifests for repo, repo name:", repoName, ", tag:", tag, ", error:", err) - ra.RenderError(500, "Internal Server Error") + ra.RenderError(http.StatusInternalServerError, "Internal Server Error") return } else { mani := Manifest{} err = json.Unmarshal(result, &mani) if err != nil { beego.Error("Failed to decode json from response for manifests, repo name:", repoName, ", tag:", tag, ", error:", err) - ra.RenderError(500, "Internal Server Error") + ra.RenderError(http.StatusInternalServerError, "Internal Server Error") return } else { v1Compatibility := mani.History[0].V1Compatibility @@ -161,7 +162,7 @@ func (ra *RepositoryAPI) GetManifests() { err = json.Unmarshal([]byte(v1Compatibility), &item) if err != nil { beego.Error("Failed to decode V1 field for repo, repo name:", repoName, ", tag:", tag, ", error:", err) - ra.RenderError(500, "Internal Server Error") + ra.RenderError(http.StatusInternalServerError, "Internal Server Error") return } else { item.CreatedStr = item.Created.Format("2006-01-02 15:04:05") diff --git a/api/search.go b/api/search.go index 805647596..e0d7348bc 100644 --- a/api/search.go +++ b/api/search.go @@ -15,6 +15,7 @@ package api import ( + "net/http" "sort" "strings" @@ -44,7 +45,7 @@ func (n *SearchAPI) Get() { projects, err := dao.QueryRelevantProjects(userId) if err != nil { beego.Error("Failed to get projects of user id:", userId, ", error:", err) - n.CustomAbort(500, "Failed to get project search result") + n.CustomAbort(http.StatusInternalServerError, "Failed to get project search result") } projectSorter := &utils.ProjectSorter{Projects: projects} sort.Sort(projectSorter) @@ -66,7 +67,7 @@ func (n *SearchAPI) Get() { repositories, err2 := svc_utils.GetRepoFromCache() if err2 != nil { beego.Error("Failed to get repos from cache, error :", err2) - n.CustomAbort(500, "Failed to get repositories search result") + n.CustomAbort(http.StatusInternalServerError, "Failed to get repositories search result") } sort.Strings(repositories) repositoryResult := filterRepositories(repositories, projects, keyword) diff --git a/api/user.go b/api/user.go index 2df9bf454..1c3fcbc13 100644 --- a/api/user.go +++ b/api/user.go @@ -15,6 +15,7 @@ package api import ( + "net/http" "strconv" "github.com/vmware/harbor/dao" @@ -40,17 +41,17 @@ func (ua *UserAPI) Prepare() { ua.userId, err = strconv.Atoi(id) if err != nil { beego.Error("Invalid user id, error:", err) - ua.CustomAbort(400, "Invalid user Id") + ua.CustomAbort(http.StatusBadRequest, "Invalid user Id") } userQuery := models.User{UserId: ua.userId} u, err := dao.GetUser(userQuery) if err != nil { beego.Error("Error occurred in GetUser:", err) - ua.CustomAbort(500, "Internal error.") + ua.CustomAbort(http.StatusInternalServerError, "Internal error.") } if u == nil { beego.Error("User with Id:", ua.userId, "does not exist") - ua.CustomAbort(404, "") + ua.CustomAbort(http.StatusNotFound, "") } } } @@ -59,13 +60,13 @@ func (ua *UserAPI) Get() { exist, err := dao.IsAdminRole(ua.currentUid) if err != nil { beego.Error("Error occurred in IsAdminRole:", err) - ua.CustomAbort(500, "Internal error.") + ua.CustomAbort(http.StatusInternalServerError, "Internal error.") } if ua.userId == 0 { //list users if !exist { beego.Error("Current user, id:", ua.currentUid, ", does not have admin role, can not list users") - ua.RenderError(403, "User does not have admin role") + ua.RenderError(http.StatusForbidden, "User does not have admin role") return } username := ua.GetString("username") @@ -76,7 +77,7 @@ func (ua *UserAPI) Get() { userList, err := dao.ListUsers(userQuery) if err != nil { beego.Error("Failed to get data from database, error:", err) - ua.RenderError(500, "Failed to query from database") + ua.RenderError(http.StatusInternalServerError, "Failed to query from database") return } ua.Data["json"] = userList @@ -86,12 +87,12 @@ func (ua *UserAPI) Get() { u, err := dao.GetUser(userQuery) if err != nil { beego.Error("Error occurred in GetUser:", err) - ua.CustomAbort(500, "Internal error.") + ua.CustomAbort(http.StatusInternalServerError, "Internal error.") } ua.Data["json"] = u } else { beego.Error("Current user, id:", ua.currentUid, "does not have admin role, can not view other user's detail") - ua.RenderError(403, "User does not have admin role") + ua.RenderError(http.StatusForbidden, "User does not have admin role") return } ua.ServeJSON() @@ -101,11 +102,11 @@ func (ua *UserAPI) Put() { //currently only for toggle admin, so no request body exist, err := dao.IsAdminRole(ua.currentUid) if err != nil { beego.Error("Error occurred in IsAdminRole:", err) - ua.CustomAbort(500, "Internal error.") + ua.CustomAbort(http.StatusInternalServerError, "Internal error.") } if !exist { beego.Warning("current user, id:", ua.currentUid, ", does not have admin role, can not update other user's role") - ua.RenderError(403, "User does not have admin role") + ua.RenderError(http.StatusForbidden, "User does not have admin role") return } userQuery := models.User{UserId: ua.userId} @@ -116,17 +117,17 @@ func (ua *UserAPI) Delete() { exist, err := dao.IsAdminRole(ua.currentUid) if err != nil { beego.Error("Error occurred in IsAdminRole:", err) - ua.CustomAbort(500, "Internal error.") + ua.CustomAbort(http.StatusInternalServerError, "Internal error.") } if !exist { beego.Warning("current user, id:", ua.currentUid, ", does not have admin role, can not remove user") - ua.RenderError(403, "User does not have admin role") + ua.RenderError(http.StatusForbidden, "User does not have admin role") return } err = dao.DeleteUser(ua.userId) if err != nil { beego.Error("Failed to delete data from database, error:", err) - ua.RenderError(500, "Failed to delete User") + ua.RenderError(http.StatusInternalServerError, "Failed to delete User") return } } diff --git a/conf/app.conf b/conf/app.conf deleted file mode 100644 index c80279df4..000000000 --- a/conf/app.conf +++ /dev/null @@ -1,9 +0,0 @@ -appname = harbor -runmode = dev - -[lang] -types = en-US|zh-CN -names = en-US|zh-CN - -[dev] -httpport = 80 \ No newline at end of file diff --git a/conf/private_key.pem b/conf/private_key.pem deleted file mode 100644 index 6c68cacb3..000000000 --- a/conf/private_key.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQClak/4HO7EeLU0w/BhtVENPLOqU0AP2QjVUdg1qhNiDWVrbWx9 -KYHqz5Kn0n2+fxdZo3o7ZY5/2+hhgkKh1z6Kge9XGgune6z4fx2J/X2Se8WsGeQU -TiND8ngSnsCANtYFwW50SbUZPtyf5XjAfKRofZem51OxbxzN3217L/ubKwIDAQAB -AoGBAITMMuNYJwAogCGaZHOs4yMjZoIJT9bpQMQxbsi2f9UqOA/ky0I4foqKloyQ -2k6DLbXTHqBsydgwLgGKWAAiE5xIR2bPMUNSLgjbA2eLly3aOR/0FJ5n09k2EmGg -Am7tLP+6yneXWKVi3HI3NzXriVjWK94WHGGC1b9F+n5CY/2RAkEA1d62OJUNve2k -IY6/b6T0BdssFo3VFcm22vnayEL/wcYrnRfF9Pb5wM4HUUqwVelKTouivXg60GNK -ZKYAx5CtHwJBAMYAEf5u0CQ/8URcwBuMkm0LzK4AM2x1nGs7gIxAEFhu1Z4xPjVe -MtIxuHhDhlLvD760uccmo5yE72QJ1ZrYBHUCQQCAxLZMPRpoB4QyHEOREe1G9V6H -OeBZXPk2wQcEWqqo3gt2a1DqHCXl+2aWgHTJVUxDHHngwFoRDCdHkFeZ0LcbAkAj -T8/luI2WaXD16DS6tQ9IM1qFjbOeHDuRRENgv+wqWVnvpIibq/kUU5m6mRBTqh78 -u+6F/fYf6/VluftGalAhAkAukdMtt+sksq2e7Qw2dRr5GXtXjt+Otjj0NaJENmWk -a7SgAs34EOWtbd0XGYpZFrg134MzQGbweFeEUTj++e8p ------END RSA PRIVATE KEY----- diff --git a/controllers/base.go b/controllers/base.go index 1f95f830e..9f9046b0f 100644 --- a/controllers/base.go +++ b/controllers/base.go @@ -15,6 +15,7 @@ package controllers import ( + "log" "os" "strings" @@ -114,6 +115,16 @@ var langTypes []*langType func init() { + //conf/app.conf -> os.Getenv("config_path") + configPath := os.Getenv("CONFIG_PATH") + if len(configPath) != 0 { + log.Printf("Config path: %s", configPath) + beego.AppConfigPath = configPath + if err := beego.ParseConfig(); err != nil { + beego.Warning("Failed to parse config file: ", configPath, "error: ", err) + } + } + beego.AddFuncMap("i18n", i18n.Tr) langs := strings.Split(beego.AppConfig.String("lang::types"), "|") @@ -134,7 +145,6 @@ func init() { for _, lang := range langs { if err := i18n.SetMessage(lang, "static/i18n/"+"locale_"+lang+".ini"); err != nil { beego.Error("Fail to set message file:" + err.Error()) - return } } } diff --git a/controllers/item_detail.go b/controllers/item_detail.go index 391fbc04e..34761fce4 100644 --- a/controllers/item_detail.go +++ b/controllers/item_detail.go @@ -15,6 +15,7 @@ package controllers import ( + "net/http" "net/url" "os" @@ -68,7 +69,7 @@ func (idc *ItemDetailController) Get() { projectId, _ := idc.GetInt64("project_id") if CheckPublicProject(projectId) == false && (sessionUserId == nil || !CheckProjectRole(sessionUserId.(int), projectId)) { - idc.Redirect("/signIn?uri="+url.QueryEscape(idc.Ctx.Input.URI()), 302) + idc.Redirect("/signIn?uri="+url.QueryEscape(idc.Ctx.Input.URI()), http.StatusFound) } projectQuery := models.Project{ProjectId: projectId} @@ -76,11 +77,11 @@ func (idc *ItemDetailController) Get() { if err != nil { beego.Error("Error occurred in GetProjectById:", err) - idc.CustomAbort(500, "Internal error.") + idc.CustomAbort(http.StatusInternalServerError, "Internal error.") } if project == nil { - idc.Redirect("/signIn", 302) + idc.Redirect("/signIn", http.StatusFound) } idc.Data["ProjectId"] = project.ProjectId @@ -94,7 +95,7 @@ func (idc *ItemDetailController) Get() { roleList, err := dao.GetUserProjectRoles(models.User{UserId: sessionUserId.(int)}, projectId) if err != nil { beego.Error("Error occurred in GetUserProjectRoles:", err) - idc.CustomAbort(500, "Internal error.") + idc.CustomAbort(http.StatusInternalServerError, "Internal error.") } if len(roleList) > 0 { idc.Data["RoleId"] = roleList[0].RoleId diff --git a/controllers/login.go b/controllers/login.go index d907018d4..0839e483b 100644 --- a/controllers/login.go +++ b/controllers/login.go @@ -15,6 +15,8 @@ package controllers import ( + "net/http" + "github.com/vmware/harbor/models" "github.com/vmware/harbor/opt_auth" @@ -45,11 +47,11 @@ func (c *CommonController) Login() { user, err := opt_auth.Login(models.AuthModel{principal, password}) if err != nil { beego.Error("Error occurred in UserLogin:", err) - c.CustomAbort(500, "Internal error.") + c.CustomAbort(http.StatusInternalServerError, "Internal error.") } if user == nil { - c.CustomAbort(401, "") + c.CustomAbort(http.StatusUnauthorized, "") } c.SetSession("userId", user.UserId) @@ -62,7 +64,7 @@ func (c *CommonController) SwitchLanguage() { c.SetSession("lang", lang) c.Data["Lang"] = lang } - c.Redirect(c.Ctx.Request.Header.Get("Referer"), 302) + c.Redirect(c.Ctx.Request.Header.Get("Referer"), http.StatusFound) } func (c *CommonController) Logout() { diff --git a/controllers/password.go b/controllers/password.go index e6211d413..aede09a0d 100644 --- a/controllers/password.go +++ b/controllers/password.go @@ -16,6 +16,7 @@ package controllers import ( "bytes" + "net/http" "os" "regexp" "text/template" @@ -34,7 +35,7 @@ type ChangePasswordController struct { func (cpc *ChangePasswordController) Get() { sessionUserId := cpc.GetSession("userId") if sessionUserId == nil { - cpc.Redirect("/signIn", 302) + cpc.Redirect("/signIn", http.StatusFound) } cpc.Data["Username"] = cpc.GetSession("username") cpc.ForwardTo("page_title_change_password", "change-password") @@ -43,32 +44,40 @@ func (cpc *ChangePasswordController) Get() { func (cpc *CommonController) UpdatePassword() { sessionUserId := cpc.GetSession("userId") - sessionUsername := cpc.GetSession("username") - if sessionUserId == nil || sessionUsername == nil { + if sessionUserId == nil { beego.Warning("User does not login.") - cpc.CustomAbort(401, "please_login_first") + cpc.CustomAbort(http.StatusUnauthorized, "please_login_first") } oldPassword := cpc.GetString("old_password") - queryUser := models.User{UserId: sessionUserId.(int), Username: sessionUsername.(string), Password: oldPassword} + if oldPassword == "" { + beego.Error("Old password is blank") + cpc.CustomAbort(http.StatusBadRequest, "Old password is blank") + } + + queryUser := models.User{UserId: sessionUserId.(int), Password: oldPassword} user, err := dao.CheckUserPassword(queryUser) if err != nil { beego.Error("Error occurred in CheckUserPassword:", err) - cpc.CustomAbort(500, "Internal error.") + cpc.CustomAbort(http.StatusInternalServerError, "Internal error.") } if user == nil { beego.Warning("Password input is not correct") - cpc.CustomAbort(403, "old_password_is_not_correct") + cpc.CustomAbort(http.StatusForbidden, "old_password_is_not_correct") } password := cpc.GetString("password") if password != "" { - updateUser := models.User{UserId: sessionUserId.(int), Username: sessionUsername.(string), Password: password, Salt: user.Salt} - dao.ChangeUserPassword(updateUser) + updateUser := models.User{UserId: sessionUserId.(int), Password: password, Salt: user.Salt} + err = dao.ChangeUserPassword(updateUser, oldPassword) + if err != nil { + beego.Error("Error occurred in ChangeUserPassword:", err) + cpc.CustomAbort(http.StatusInternalServerError, "Internal error.") + } } else { - cpc.CustomAbort(404, "please_input_new_password") + cpc.CustomAbort(http.StatusBadRequest, "please_input_new_password") } } @@ -90,22 +99,26 @@ func (fpc *CommonController) SendEmail() { email := fpc.GetString("email") - if ok, _ := 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); ok { + 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 { + fpc.CustomAbort(http.StatusBadRequest, "email_content_illegal") + } else { queryUser := models.User{Email: email} exist, err := dao.UserExists(queryUser, "email") if err != nil { beego.Error("Error occurred in UserExists:", err) - fpc.CustomAbort(500, "Internal error.") + fpc.CustomAbort(http.StatusInternalServerError, "Internal error.") } if !exist { - fpc.CustomAbort(404, "email_does_not_exist") + fpc.CustomAbort(http.StatusNotFound, "email_does_not_exist") } messageTemplate, err := template.ParseFiles("views/reset-password-mail.tpl") if err != nil { beego.Error("Parse email template file failed:", err) - fpc.CustomAbort(500, err.Error()) + fpc.CustomAbort(http.StatusInternalServerError, err.Error()) } message := new(bytes.Buffer) @@ -117,7 +130,7 @@ func (fpc *CommonController) SendEmail() { uuid, err := dao.GenerateRandomString() if err != nil { beego.Error("Error occurred in GenerateRandomString:", err) - fpc.CustomAbort(500, "Internal error.") + fpc.CustomAbort(http.StatusInternalServerError, "Internal error.") } err = messageTemplate.Execute(message, MessageDetail{ Hint: fpc.Tr("reset_email_hint"), @@ -127,13 +140,13 @@ func (fpc *CommonController) SendEmail() { if err != nil { beego.Error("message template error:", err) - fpc.CustomAbort(500, "internal_error") + fpc.CustomAbort(http.StatusInternalServerError, "internal_error") } config, err := beego.AppConfig.GetSection("mail") if err != nil { beego.Error("Can not load app.conf:", err) - fpc.CustomAbort(500, "internal_error") + fpc.CustomAbort(http.StatusInternalServerError, "internal_error") } mail := utils.Mail{ @@ -146,14 +159,12 @@ func (fpc *CommonController) SendEmail() { if err != nil { beego.Error("send email failed:", err) - fpc.CustomAbort(500, "send_email_failed") + fpc.CustomAbort(http.StatusInternalServerError, "send_email_failed") } user := models.User{ResetUuid: uuid, Email: email} dao.UpdateUserResetUuid(user) - } else { - fpc.CustomAbort(409, "email_content_illegal") } } @@ -164,39 +175,55 @@ type ResetPasswordController struct { func (rpc *ResetPasswordController) Get() { - q := rpc.GetString("q") - queryUser := models.User{ResetUuid: q} + resetUuid := rpc.GetString("reset_uuid") + if resetUuid == "" { + beego.Error("Reset uuid is blank.") + rpc.Redirect("/", http.StatusFound) + } + + queryUser := models.User{ResetUuid: resetUuid} user, err := dao.GetUser(queryUser) if err != nil { beego.Error("Error occurred in GetUser:", err) - rpc.CustomAbort(500, "Internal error.") + rpc.CustomAbort(http.StatusInternalServerError, "Internal error.") } if user != nil { rpc.Data["ResetUuid"] = user.ResetUuid rpc.ForwardTo("page_title_reset_password", "reset-password") } else { - rpc.Redirect("/", 302) + rpc.Redirect("/", http.StatusFound) } } func (rpc *CommonController) ResetPassword() { resetUuid := rpc.GetString("reset_uuid") + if resetUuid == "" { + rpc.CustomAbort(http.StatusBadRequest, "Reset uuid is blank.") + } queryUser := models.User{ResetUuid: resetUuid} user, err := dao.GetUser(queryUser) if err != nil { beego.Error("Error occurred in GetUser:", err) - rpc.CustomAbort(500, "Internal error.") + rpc.CustomAbort(http.StatusInternalServerError, "Internal error.") + } + if user == nil { + beego.Error("User does not exist") + rpc.CustomAbort(http.StatusBadRequest, "User does not exist") } password := rpc.GetString("password") if password != "" { user.Password = password - dao.ResetUserPassword(*user) + err = dao.ResetUserPassword(*user) + if err != nil { + beego.Error("Error occurred in ResetUserPassword:", err) + rpc.CustomAbort(http.StatusInternalServerError, "Internal error.") + } } else { - rpc.CustomAbort(404, "password_is_required") + rpc.CustomAbort(http.StatusBadRequest, "password_is_required") } } diff --git a/controllers/register.go b/controllers/register.go index 244770419..7f8553ae5 100644 --- a/controllers/register.go +++ b/controllers/register.go @@ -15,6 +15,7 @@ package controllers import ( + "net/http" "os" "strings" @@ -33,7 +34,7 @@ func (rc *RegisterController) Get() { if authMode == "" || authMode == "db_auth" { rc.ForwardTo("page_title_registration", "register") } else { - rc.Redirect("/signIn", 404) + rc.Redirect("/signIn", http.StatusNotFound) } } @@ -49,7 +50,7 @@ func (rc *CommonController) SignUp() { _, err := dao.Register(user) if err != nil { beego.Error("Error occurred in Register:", err) - rc.CustomAbort(500, "Internal error.") + rc.CustomAbort(http.StatusInternalServerError, "Internal error.") } } @@ -68,7 +69,7 @@ func (rc *CommonController) UserExists() { exist, err := dao.UserExists(user, target) if err != nil { beego.Error("Error occurred in UserExists:", err) - rc.CustomAbort(500, "Internal error.") + rc.CustomAbort(http.StatusInternalServerError, "Internal error.") } rc.Data["json"] = exist rc.ServeJSON() diff --git a/dao/access_log.go b/dao/access_log.go index 4e99cfdb8..5860a30c3 100644 --- a/dao/access_log.go +++ b/dao/access_log.go @@ -73,13 +73,13 @@ func GetAccessLogs(accessLog models.AccessLog) ([]models.AccessLog, error) { } } } - if accessLog.BeginTime != "" { - sql += ` and a.op_time >= str_to_date(?, '%Y-%m-%d %H:%i:%s') ` - queryParam = append(queryParam, accessLog.BeginTime+" 00:00:00.000000") + if accessLog.BeginTimestamp > 0 { + sql += ` and a.op_time >= ? ` + queryParam = append(queryParam, accessLog.BeginTime) } - if accessLog.EndTime != "" { - sql += ` and a.op_time <= str_to_date(?, '%Y-%m-%d %H:%i:%s') ` - queryParam = append(queryParam, accessLog.EndTime+" 23:59:59.99999") + if accessLog.EndTimestamp > 0 { + sql += ` and a.op_time <= ? ` + queryParam = append(queryParam, accessLog.EndTime) } sql += ` order by a.op_time desc ` diff --git a/dao/base.go b/dao/base.go index d6e8f37a9..90ba82143 100644 --- a/dao/base.go +++ b/dao/base.go @@ -1,16 +1,16 @@ /* - 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. + 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. */ package dao @@ -50,18 +50,17 @@ func isContainIllegalChar(s string, illegalChar []string) bool { func GenerateRandomString() (string, error) { o := orm.NewOrm() - var salt string - err := o.Raw(`select uuid() as uuid`).QueryRow(&salt) + var uuid string + err := o.Raw(`select uuid() as uuid`).QueryRow(&uuid) if err != nil { return "", err } - return salt, nil + return uuid, nil } -func init() { +func InitDB() { orm.RegisterDriver("mysql", orm.DRMySQL) - addr := os.Getenv("MYSQL_HOST") if len(addr) == 0 { addr = os.Getenv("MYSQL_PORT_3306_TCP_ADDR") @@ -112,8 +111,11 @@ func init() { }() select { case <-ch: - case <-time.After(30 * time.Second): - panic("Failed to connect to DB after 30 seconds") + case <-time.After(60 * time.Second): + panic("Failed to connect to DB after 60 seconds") + } + err := orm.RegisterDataBase("default", "mysql", db_str) + if err != nil { + panic(err) } - orm.RegisterDataBase("default", "mysql", db_str) } diff --git a/dao/user.go b/dao/user.go index e215712f4..a0a259cc5 100644 --- a/dao/user.go +++ b/dao/user.go @@ -15,6 +15,9 @@ package dao import ( + "database/sql" + "errors" + "github.com/vmware/harbor/models" "github.com/vmware/harbor/utils" @@ -133,15 +136,44 @@ func ToggleUserAdminRole(u models.User) error { return err } -func ChangeUserPassword(u models.User) error { +func ChangeUserPassword(u models.User, oldPassword ...string) error { o := orm.NewOrm() - _, err := o.Raw(`update user set password=?, salt=? where user_id=?`, utils.Encrypt(u.Password, u.Salt), u.Salt, u.UserId).Exec() + var err error + var r sql.Result + if len(oldPassword) == 0 { + //In some cases, it may no need to check old password, just as Linux change password policies. + _, err = o.Raw(`update user set password=?, salt=? where user_id=?`, utils.Encrypt(u.Password, u.Salt), u.Salt, u.UserId).Exec() + } else if len(oldPassword) == 1 { + 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() + if err != nil { + return err + } + count, err := r.RowsAffected() + if err != nil { + return err + } + if count == 0 { + return errors.New("No record be changed, change password failed.") + } + } else { + return errors.New("Wrong numbers of params.") + } return err } func ResetUserPassword(u models.User) error { o := orm.NewOrm() - _, err := o.Raw(`update user set password=?, reset_uuid=? where reset_uuid=?`, utils.Encrypt(u.Password, u.Salt), "", u.ResetUuid).Exec() + r, err := o.Raw(`update user set password=?, reset_uuid=? where reset_uuid=?`, utils.Encrypt(u.Password, u.Salt), "", u.ResetUuid).Exec() + if err != nil { + return err + } + count, err := r.RowsAffected() + if err != nil { + return err + } + if count == 0 { + return errors.New("No record be changed, reset password failed.") + } return err } diff --git a/main.go b/main.go index 86e8ee87d..531372297 100644 --- a/main.go +++ b/main.go @@ -38,7 +38,7 @@ func updateInitPassword(userId int, password string) error { queryUser := models.User{UserId: userId} user, err := dao.GetUser(queryUser) if err != nil { - log.Println("Failed to get user in initial password, userId:", userId) + log.Println("Failed to get user, userId:", userId) return err } if user == nil { @@ -67,15 +67,7 @@ func updateInitPassword(userId int, password string) error { func main() { beego.BConfig.WebConfig.Session.SessionOn = true - - //conf/app.conf -> os.Getenv("config_path") - configPath := os.Getenv("CONFIG_PATH") - if len(configPath) != 0 { - beego.Debug(fmt.Sprintf("Config path: %s", configPath)) - beego.AppConfigPath = configPath - } - + dao.InitDB() updateInitPassword(ADMIN_USER_ID, os.Getenv("HARBOR_ADMIN_PASSWORD")) - beego.Run() } diff --git a/models/access_log.go b/models/access_log.go index 7c980103d..a167d70de 100644 --- a/models/access_log.go +++ b/models/access_log.go @@ -26,10 +26,11 @@ type AccessLog struct { Guid string Operation string OpTime time.Time - OpTimeStr string - Username string Keywords string - BeginTime string - EndTime string + + BeginTime time.Time + BeginTimestamp int64 + EndTime time.Time + EndTimestamp int64 } diff --git a/service/auth.go b/service/auth.go index f405ee9ce..bfa3dfd68 100644 --- a/service/auth.go +++ b/service/auth.go @@ -16,6 +16,7 @@ package service import ( "log" + "net/http" "github.com/vmware/harbor/models" "github.com/vmware/harbor/opt_auth" @@ -46,7 +47,7 @@ func (a *AuthController) Auth() { if len(scope) == 0 && !authenticated { log.Printf("login request with invalid credentials") - a.CustomAbort(401, "") + a.CustomAbort(http.StatusUnauthorized, "") } access := svc_utils.GetResourceActions(scope) for _, a := range access { @@ -61,7 +62,7 @@ func (a *AuthController) serveToken(username, service string, access []*token.Re rawToken, err := svc_utils.MakeToken(username, service, access) if err != nil { log.Printf("Failed to make token, error: %v", err) - writer.WriteHeader(500) + writer.WriteHeader(http.StatusInternalServerError) return } tk := make(map[string]string) diff --git a/service/utils/registry_utils.go b/service/utils/registry_utils.go index 8c8892d5b..aa5def9e6 100644 --- a/service/utils/registry_utils.go +++ b/service/utils/registry_utils.go @@ -50,9 +50,9 @@ func RegistryApiGet(url, username string) ([]byte, error) { return nil, err } defer response.Body.Close() - if response.StatusCode == 200 { + if response.StatusCode == http.StatusOK { return result, nil - } else if response.StatusCode == 401 { + } else if response.StatusCode == http.StatusUnauthorized { authenticate := response.Header.Get("WWW-Authenticate") str := strings.Split(authenticate, " ")[1] log.Println("url: " + url) @@ -94,7 +94,7 @@ func RegistryApiGet(url, username string) ([]byte, error) { if err != nil { return nil, err } - if response.StatusCode != 200 { + if response.StatusCode != http.StatusOK { errMsg := fmt.Sprintf("Unexpected return code from registry: %d", response.StatusCode) log.Printf(errMsg) return nil, fmt.Errorf(errMsg) diff --git a/static/resources/js/item-detail.js b/static/resources/js/item-detail.js index d2ff211bb..764df0fe6 100644 --- a/static/resources/js/item-detail.js +++ b/static/resources/js/item-detail.js @@ -374,24 +374,38 @@ jQuery(function(){ listUser(username); }); + function toUTCSeconds(date, hour, min, sec) { + var t = new Date(date); + t.setHours(hour); + t.setMinutes(min); + t.setSeconds(sec); + var utcTime = new Date(t.getUTCFullYear(), + t.getUTCMonth(), + t.getUTCDate(), + t.getUTCHours(), + t.getUTCMinutes(), + t.getUTCSeconds()); + return utcTime.getTime() / 1000; + } + $("#btnFilterLog").on("click", function(){ var projectId = $("#projectId").val(); var username = $("#txtSearchUserName").val(); - var beginTime = ""; - var endTime = ""; + var beginTimestamp = 0; + var endTimestamp = 0; if($("#begindatepicker").val() != ""){ - beginTime = moment(new Date($("#begindatepicker").val())).format("YYYY-MM-DD"); + beginTimestamp = toUTCSeconds($("#begindatepicker").val(), 0, 0, 0); } if($("#enddatepicker").val() != ""){ - endTime = moment(new Date($("#enddatepicker").val())).format("YYYY-MM-DD"); + endTimestamp = toUTCSeconds($("#enddatepicker").val(), 23, 59, 59); } new AjaxUtil({ url: "/api/projects/" + projectId + "/logs/filter", - data:{"username":username, "project_id" : projectId, "keywords" : getKeyWords() , "beginTime" : beginTime, "endTime" : endTime}, + data:{"username":username, "project_id" : projectId, "keywords" : getKeyWords() , "beginTimestamp" : beginTimestamp, "endTimestamp" : endTimestamp}, type: "post", success: function(data, status, xhr){ if(xhr && xhr.status == 200){ diff --git a/tests/dao_test.go b/tests/dao_test.go index 9d39b3037..0179da876 100644 --- a/tests/dao_test.go +++ b/tests/dao_test.go @@ -15,8 +15,8 @@ package test import ( - "flag" "fmt" + // "fmt" "log" "os" "testing" @@ -85,9 +85,7 @@ func clearUp(username string) { } const USERNAME string = "Tester01" - const PROJECT_NAME string = "test_project" - const SYS_ADMIN int = 1 const PROJECT_ADMIN int = 2 const DEVELOPER int = 3 @@ -98,35 +96,37 @@ const PUBLICITY_OFF = 0 func TestMain(m *testing.M) { - //Create a custom flag set, let user to provide DB related configures for testing. - fs := flag.NewFlagSet("DB related configures", 0) - - dbIp := fs.String("db_ip", "localhost", "IP address for connecting a test DB.") - dbPort := fs.String("db_port", "3306", "Port number for connecting a test DB.") - dbUser := fs.String("db_user", "root", "Username for logging in a test DB.") - dbPassword := fs.String("db_password", "root", "Password for logging in a test DB.") - - fs.Parse([]string{"db_ip", "db_port", "db_user", "db_password"}) - - if fs.NFlag() == 0 { - fs.PrintDefaults() - fmt.Println("Now, use DEFAULT values if omit to set all of flags.") + dbHost := os.Getenv("DB_HOST") + if len(dbHost) == 0 { + log.Fatalf("environment variable DB_HOST is not set") + } + dbUser := os.Getenv("DB_USR") + if len(dbUser) == 0 { + log.Fatalf("environment variable DB_USR is not set") + } + dbPort := os.Getenv("DB_PORT") + if len(dbPort) == 0 { + log.Fatalf("environment variable DB_PORT is not set") + } + dbPassword := os.Getenv("DB_PWD") + if len(dbPassword) == 0 { + log.Fatalf("environment variable DB_PWD is not set") } - if fs.Parsed() { + fmt.Printf("DB_HOST: %s, DB_USR: %s, DB_PORT: %s, DB_PWD: %s\n", dbHost, dbUser, dbPort, dbPassword) - clearUp(USERNAME) + os.Setenv("MYSQL_PORT_3306_TCP_ADDR", dbHost) + os.Setenv("MYSQL_PORT_3306_TCP_PORT", dbPort) + os.Setenv("MYSQL_USR", dbUser) + os.Setenv("MYSQL_PWD", dbPassword) + os.Setenv("AUTH_MODE", "db_auth") + dao.InitDB() + clearUp(USERNAME) + os.Exit(m.Run()) - os.Setenv("MYSQL_PORT_3306_TCP_ADDR", *dbIp) - os.Setenv("MYSQL_PORT_3306_TCP_PORT", *dbPort) - os.Setenv("MYSQL_USR", *dbUser) - os.Setenv("MYSQL_PWD", *dbPassword) - os.Setenv("AUTH_MODE", "db_auth") - os.Exit(m.Run()) - } } -func ExampleRegister() { +func TestRegister(t *testing.T) { user := models.User{ Username: USERNAME, @@ -138,7 +138,7 @@ func ExampleRegister() { _, err := dao.Register(user) if err != nil { - log.Printf("Error occurred in Register: %v", err) + t.Errorf("Error occurred in Register: %v", err) } //Check if user registered successfully. @@ -147,41 +147,46 @@ func ExampleRegister() { } newUser, err := dao.GetUser(queryUser) if err != nil { - log.Fatalf("Error occurred in GetUser: %v", err) + t.Errorf("Error occurred in GetUser: %v", err) } - fmt.Println(newUser.Username) - fmt.Println(newUser.Email) - // Output: - // Tester01 - // tester01@vmware.com - + if newUser.Username != USERNAME { + t.Errorf("Username does not match, expected: %s, actual: %s", USERNAME, newUser.Username) + } + if newUser.Email != "tester01@vmware.com" { + t.Errorf("Email does not match, expected: %s, actual: %s", "tester01@vmware.com", newUser.Email) + } } -func ExampleUserExists() { +func TestUserExists(t *testing.T) { var exists bool var err error - exists, err = dao.UserExists(models.User{Username: "Tester01"}, "username") - fmt.Println(exists) - + exists, err = dao.UserExists(models.User{Username: USERNAME}, "username") if err != nil { - log.Fatalf("Error occurred in UserExists: %v", err) + t.Errorf("Error occurred in UserExists: %v", err) + } + if !exists { + t.Errorf("User %s was inserted but does not exist", USERNAME) } exists, err = dao.UserExists(models.User{Email: "tester01@vmware.com"}, "email") - fmt.Println(exists) if err != nil { - log.Fatalf("Error occurred in UserExists: %v", err) + t.Errorf("Error occurred in UserExists: %v", err) + } + if !exists { + t.Errorf("User with email %s inserted but does not exist", "tester01@vmware.com") + } + exists, err = dao.UserExists(models.User{Username: "NOTHERE"}, "username") + if err != nil { + t.Errorf("Error occurred in UserExists: %v", err) + } + if exists { + t.Errorf("User %s was not inserted but does exist", "NOTHERE") } - - //Output: - //true - //true - } -func ExampleLoginByUserName() { +func TestLoginByUserName(t *testing.T) { userQuery := models.User{ Username: USERNAME, @@ -190,18 +195,18 @@ func ExampleLoginByUserName() { loginUser, err := dao.LoginByDb(models.AuthModel{userQuery.Username, userQuery.Password}) if err != nil { - log.Fatalf("Error occurred in LoginByDb: %v", err) + t.Errorf("Error occurred in LoginByDb: %v", err) } if loginUser == nil { - log.Fatalf("No found for user logined by username and password: %v", userQuery) + t.Errorf("No found for user logined by username and password: %v", userQuery) } - fmt.Println(loginUser.Username) - // Output: - // Tester01 + if loginUser.Username != USERNAME { + t.Errorf("User's username does not match after login, expected: %s, actual: %s", USERNAME, loginUser.Username) + } } -func ExampleLoginByEmail() { +func TestLoginByEmail(t *testing.T) { userQuery := models.User{ Email: "tester01@vmware.com", @@ -210,105 +215,136 @@ func ExampleLoginByEmail() { loginUser, err := dao.LoginByDb(models.AuthModel{userQuery.Email, userQuery.Password}) if err != nil { - log.Fatalf("Error occurred in LoginByDb: %v", err) + t.Errorf("Error occurred in LoginByDb: %v", err) } if loginUser == nil { - log.Fatalf("No found for user logined by email and password : %v", userQuery) + t.Errorf("No found for user logined by email and password : %v", userQuery) + } + if loginUser.Username != USERNAME { + t.Errorf("User's username does not match after login, expected: %s, actual: %s", USERNAME, loginUser.Username) } - fmt.Println(loginUser.Username) - // Output: - // Tester01 } var currentUser *models.User -func ExampleGetUser() { +func TestGetUser(t *testing.T) { queryUser := models.User{ Username: USERNAME, } var err error currentUser, err = dao.GetUser(queryUser) if err != nil { - log.Fatalf("Error occurred in GetUser", err) + t.Errorf("Error occurred in GetUser: %v", err) } if currentUser == nil { - log.Fatalf("No user found queried by username: %v", queryUser) + t.Errorf("No user found queried by user query: %+v", queryUser) + } + if currentUser.Email != "tester01@vmware.com" { + t.Errorf("the user's email does not match, expected: tester01@vmware.com, actual: %s", currentUser.Email) } - fmt.Println(currentUser.Username) - //Output: - //Tester01 } -func ExampleListUsers() { - users, err := dao.ListUsers(models.User{Username: "tester01"}) +func TestListUsers(t *testing.T) { + users, err := dao.ListUsers(models.User{}) if err != nil { - log.Fatalf("Error occurred in ListUsers: %v", err) + t.Errorf("Error occurred in ListUsers: %v", err) } - - for _, u := range users { - fmt.Println(u.Username) + if len(users) != 1 { + t.Errorf("Expect one user in list, but the acutal length is %d, the list: %+v", len(users), users) + } + users2, err := dao.ListUsers(models.User{Username: USERNAME}) + if len(users2) != 1 { + t.Errorf("Expect one user in list, but the acutal length is %d, the list: %+v", len(users), users) + } + if users2[0].Username != USERNAME { + t.Errorf("The username in result list does not match, expected: %s, actual: %s", USERNAME, users2[0].Username) } - //Output: - //Tester01 } -func ExampleResetUserPassword() { +func TestResetUserPassword(t *testing.T) { uuid, err := dao.GenerateRandomString() if err != nil { - log.Fatalf("Error occurred in GenerateRandomString: %v", err) + t.Errorf("Error occurred in GenerateRandomString: %v", err) } err = dao.UpdateUserResetUuid(models.User{ResetUuid: uuid, Email: currentUser.Email}) if err != nil { - log.Fatalf("Error occurred in UpdateUserResetUuid: %v", err) + t.Errorf("Error occurred in UpdateUserResetUuid: %v", err) } err = dao.ResetUserPassword(models.User{UserId: currentUser.UserId, Password: "HarborTester12345", ResetUuid: uuid, Salt: currentUser.Salt}) if err != nil { - log.Fatalf("Error occurred in ResetUserPassword: %v", err) + t.Errorf("Error occurred in ResetUserPassword: %v", err) } loginedUser, err := dao.LoginByDb(models.AuthModel{Principal: currentUser.Username, Password: "HarborTester12345"}) if err != nil { - log.Fatalf("Error occurred in LoginByDb: %v", err) + t.Errorf("Error occurred in LoginByDb: %v", err) } - fmt.Println(loginedUser.Username) - //Output: - //Tester01 + if loginedUser.Username != USERNAME { + t.Errorf("The username returned by Login does not match, expected: %s, acutal: %s", USERNAME, loginedUser.Username) + } } -func ExampleChangeUserPassword() { +func TestChangeUserPassword(t *testing.T) { err := dao.ChangeUserPassword(models.User{UserId: currentUser.UserId, Password: "NewHarborTester12345", Salt: currentUser.Salt}) if err != nil { - log.Fatalf("Error occurred in ChangeUserPassword: %v", err) + t.Errorf("Error occurred in ChangeUserPassword: %v", err) } loginedUser, err := dao.LoginByDb(models.AuthModel{Principal: currentUser.Username, Password: "NewHarborTester12345"}) if err != nil { - log.Fatalf("Error occurred in LoginByDb: %v", err) + t.Errorf("Error occurred in LoginByDb: %v", err) } - fmt.Println(loginedUser.Username) - //Output: - //Tester01 + if loginedUser.Username != USERNAME { + t.Errorf("The username returned by Login does not match, expected: %s, acutal: %s", USERNAME, loginedUser.Username) + } } -func ExampleQueryRelevantProjectsWhenNoProjectAdded() { +func TestChangeUserPasswordWithOldPassword(t *testing.T) { + err := dao.ChangeUserPassword(models.User{UserId: currentUser.UserId, Password: "NewerHarborTester12345", Salt: currentUser.Salt}, "NewHarborTester12345") + if err != nil { + t.Errorf("Error occurred in ChangeUserPassword: %v", err) + } + loginedUser, err := dao.LoginByDb(models.AuthModel{Principal: currentUser.Username, Password: "NewerHarborTester12345"}) + if err != nil { + t.Errorf("Error occurred in LoginByDb: %v", err) + } + if loginedUser.Username != USERNAME { + t.Errorf("The username returned by Login does not match, expected: %s, acutal: %s", USERNAME, loginedUser.Username) + } +} + +func TestChangeUserPasswordWithIncorrectOldPassword(t *testing.T) { + err := dao.ChangeUserPassword(models.User{UserId: currentUser.UserId, Password: "NNewerHarborTester12345", Salt: currentUser.Salt}, "WrongNewerHarborTester12345") + if err == nil { + t.Errorf("Error does not occurred due to old password is incorrect.") + } + loginedUser, err := dao.LoginByDb(models.AuthModel{Principal: currentUser.Username, Password: "NNewerHarborTester12345"}) + if err != nil { + t.Errorf("Error occurred in LoginByDb: %v", err) + } + if loginedUser != nil { + t.Errorf("The login user is not nil, acutal: %+v", loginedUser) + } +} + +func TestQueryRelevantProjectsWhenNoProjectAdded(t *testing.T) { projects, err := dao.QueryRelevantProjects(currentUser.UserId) if err != nil { - log.Fatalf("Error occurred in QueryRelevantProjects: %v", err) + t.Errorf("Error occurred in QueryRelevantProjects: %v", err) } - fmt.Println(len(projects)) - for _, p := range projects { - fmt.Println(p.Name) + if len(projects) != 1 { + t.Errorf("Expected only one project in DB, but actual: %d", len(projects)) + } + if projects[0].Name != "library" { + t.Errorf("There name of the project does not match, expected: %s, actual: %s", "library", projects[0].Name) } - //Output: - //1 - //library } -func ExampleAddProject() { +func TestAddProject(t *testing.T) { project := models.Project{ OwnerId: currentUser.UserId, @@ -319,134 +355,128 @@ func ExampleAddProject() { err := dao.AddProject(project) if err != nil { - log.Fatalf("Error occurred in AddProject: %v", err) + t.Errorf("Error occurred in AddProject: %v", err) } newProject, err := dao.GetProjectByName(PROJECT_NAME) if err != nil { - log.Fatalf("Error occurred in GetProjectByName: %v", err) + t.Errorf("Error occurred in GetProjectByName: %v", err) } if newProject == nil { - log.Fatalf("No project found queried by project name: %v", PROJECT_NAME) + t.Errorf("No project found queried by project name: %v", PROJECT_NAME) } - fmt.Println(newProject.Name) - //Output: - //test_project } var currentProject *models.Project -func ExampleGetProject() { +func TestGetProject(t *testing.T) { var err error currentProject, err = dao.GetProjectByName(PROJECT_NAME) if err != nil { - log.Fatalf("Error occurred in GetProjectByName: %v", err) + t.Errorf("Error occurred in GetProjectByName: %v", err) } if currentProject == nil { - log.Fatalf("No project found queried by project name: %v", PROJECT_NAME) + t.Errorf("No project found queried by project name: %v", PROJECT_NAME) + } + if currentProject.Name != PROJECT_NAME { + t.Errorf("Project name does not match, expected: %s, actual: %s", PROJECT_NAME, currentProject.Name) } - fmt.Println(currentProject.Name) - //Output: - //test_project } func getProjectRole(projectId int64) []models.Role { o := orm.NewOrm() var r []models.Role _, err := o.Raw(`select r.role_id, r.name - from project_role pr + from project_role pr left join role r on pr.role_id = r.role_id where project_id = ?`, projectId).QueryRows(&r) if err != nil { - log.Fatalf("Error occurred in querying project_role: %v", err) + log.Printf("Error occurred in querying project_role: %v", err) } return r } -func ExampleCheckProjectRoles() { +func TestCheckProjectRoles(t *testing.T) { r := getProjectRole(currentProject.ProjectId) - fmt.Println(len(r)) - - for _, pr := range r { - fmt.Println(pr.RoleId, pr.Name) + if len(r) != 3 { + t.Errorf("The length of project roles is not 3") + } + if r[1].RoleId != 3 { + t.Errorf("The role id does not match, expected: 3, acutal: %d", r[1].RoleId) + } + if r[1].Name != "developer" { + t.Errorf("The name of role id: 3 should be developer, actual:%s", r[1].Name) } - - //Output: 3 - //2 projectAdmin - //3 developer - //4 guest - } -func ExampleGetAccessLog() { +func TestGetAccessLog(t *testing.T) { queryAccessLog := models.AccessLog{ UserId: currentUser.UserId, ProjectId: currentProject.ProjectId, } accessLogs, err := dao.GetAccessLogs(queryAccessLog) if err != nil { - log.Fatalf("Error occurred in GetAccessLog: %v", err) + t.Errorf("Error occurred in GetAccessLog: %v", err) } - fmt.Println(len(accessLogs)) - for _, log := range accessLogs { - fmt.Println(log.Operation, log.RepoName) + if len(accessLogs) != 1 { + t.Errorf("The length of accesslog list should be 1, actual: %d", len(accessLogs)) + } + if accessLogs[0].RepoName != PROJECT_NAME+"/" { + t.Errorf("The project name does not match, expected: %s, actual: %s", PROJECT_NAME+"/", accessLogs[0].RepoName) } - //Output: - //1 - //create test_project/ } -func ExampleProjectExists() { +func TestProjectExists(t *testing.T) { var exists bool var err error exists, err = dao.ProjectExists(currentProject.ProjectId) - fmt.Println(exists) if err != nil { - log.Fatalf("Error occurred in ProjectExists: %v", err) + t.Errorf("Error occurred in ProjectExists: %v", err) + } + if !exists { + t.Errorf("The project with id: %d, does not exist", currentProject.ProjectId) } exists, err = dao.ProjectExists(currentProject.Name) - fmt.Println(exists) if err != nil { - log.Fatalf("Error occurred in ProjectExists: %v", err) + t.Errorf("Error occurred in ProjectExists: %v", err) + } + if !exists { + t.Errorf("The project with name: %s, does not exist", currentProject.Name) } - //Output: - //true - //true - } -func ExampleToggleProjectPublicity() { +func TestToggleProjectPublicity(t *testing.T) { err := dao.ToggleProjectPublicity(currentProject.ProjectId, PUBLICITY_ON) if err != nil { - log.Fatalf("Error occurred in ToggleProjectPublicity: %v", err) + t.Errorf("Error occurred in ToggleProjectPublicity: %v", err) } currentProject, err = dao.GetProjectByName(PROJECT_NAME) if err != nil { - log.Fatalf("Error occurred in GetProjectByName: %v", err) + t.Errorf("Error occurred in GetProjectByName: %v", err) + } + if currentProject.Public != PUBLICITY_ON { + t.Errorf("project, id: %d, its publicity is not on", currentProject.ProjectId) } - fmt.Println(currentProject.Public) - err = dao.ToggleProjectPublicity(currentProject.ProjectId, PUBLICITY_OFF) if err != nil { - log.Fatalf("Error occurred in ToggleProjectPublicity: %v", err) + t.Errorf("Error occurred in ToggleProjectPublicity: %v", err) } currentProject, err = dao.GetProjectByName(PROJECT_NAME) if err != nil { - log.Fatalf("Error occurred in GetProjectByName: %v", err) + t.Errorf("Error occurred in GetProjectByName: %v", err) } - fmt.Println(currentProject.Public) - //Output: - //1 - //0 + if currentProject.Public != PUBLICITY_OFF { + t.Errorf("project, id: %d, its publicity is not off", currentProject.ProjectId) + } } func getUserProjectRole(projectId int64, userId int) []models.Role { o := orm.NewOrm() var r []models.Role - _, err := o.Raw(`select r.role_id, r.name + _, err := o.Raw(`select r.role_id, r.name from user_project_role upr left join project_role pr on upr.pr_id = pr.pr_id left join role r on r.role_id = pr.role_id @@ -457,99 +487,83 @@ func getUserProjectRole(projectId int64, userId int) []models.Role { return r } -func ExampleGetUserProjectRole() { +func TestGetUserProjectRole(t *testing.T) { r := getUserProjectRole(currentProject.ProjectId, currentUser.UserId) //Get the size of current user project role. - fmt.Println(len(r)) - - //Iterating current user project role info. - for _, upr := range r { - fmt.Println(upr.RoleId, upr.Name) + if len(r) != 1 { + t.Errorf("The user, id: %d, should only have one role in project, id: %d, but actual: %d", currentUser.UserId, currentProject.ProjectId, len(r)) } - //Output: - //1 - //2 projectAdmin + if r[0].Name != "projectAdmin" { + t.Errorf("the expected rolename is: projectAdmin, actual: %s", r[0].Name) + } } -func ExampleProjectPermission() { +func TestProjectPermission(t *testing.T) { roleCode, err := dao.GetPermission(currentUser.Username, currentProject.Name) if err != nil { - log.Fatalf("Error occurred in GetPermission: %v", err) + t.Errorf("Error occurred in GetPermission: %v", err) + } + if roleCode != "MDRWS" { + t.Errorf("The expected role code is MDRWS,but actual: %s", roleCode) } - fmt.Println(roleCode) - //Output: - //MDRWS } -func ExampleQueryRelevantProjects() { +func TestQueryRelevantProjects(t *testing.T) { projects, err := dao.QueryRelevantProjects(currentUser.UserId) if err != nil { - log.Fatalf("Error occurred in QueryRelevantProjects: %v", err) + t.Errorf("Error occurred in QueryRelevantProjects: %v", err) } - fmt.Println(len(projects)) - for _, p := range projects { - fmt.Println(p.Name) + if len(projects) != 2 { + t.Errorf("Expected length of relevant projects is 2, but actual: %d, the projects: %+v", len(projects), projects) + } + if projects[1].Name != PROJECT_NAME { + t.Errorf("Expected project name in the list: %s, actual: %s", PROJECT_NAME, projects[1].Name) } - //Output: - //2 - //library - //test_project } -func ExampleAssignUserProjectRole() { +func TestAssignUserProjectRole(t *testing.T) { err := dao.AddUserProjectRole(currentUser.UserId, currentProject.ProjectId, DEVELOPER) if err != nil { - log.Fatalf("Error occurred in AddUserProjectRole: %v", err) + t.Errorf("Error occurred in AddUserProjectRole: %v", err) } r := getUserProjectRole(currentProject.ProjectId, currentUser.UserId) //Get the size of current user project role info. - fmt.Println(len(r)) - - //Iterating current user project role. - for _, upr := range r { - fmt.Println(upr.RoleId, upr.Name) + if len(r) != 2 { + t.Errorf("Expected length of role list is 2, actual: %d", len(r)) } - //Output: - //2 - //2 projectAdmin - //3 developer + if r[1].RoleId != 3 { + t.Errorf("Expected role id of the second role in list is 3, actual: %d", r[1].RoleId) + } } -func ExampleDeleteUserProjectRole() { +func TestDeleteUserProjectRole(t *testing.T) { err := dao.DeleteUserProjectRoles(currentUser.UserId, currentProject.ProjectId) if err != nil { - log.Fatalf("Error occurred in DeleteUserProjectRoles: %v", err) + t.Errorf("Error occurred in DeleteUserProjectRoles: %v", err) } r := getUserProjectRole(currentProject.ProjectId, currentUser.UserId) - //Get the size of current user project role. - fmt.Println(len(r)) - - //Iterating current user project role info. - for _, upr := range r { - fmt.Println(upr.RoleId, upr.Name) + if len(r) != 0 { + t.Errorf("Expected role list length is 0, actual: %d, role list: %+v", len(r), r) } - - //Output: - //0 } -func ExampleDeleteUser() { +func TestDeleteUser(t *testing.T) { err := dao.DeleteUser(currentUser.UserId) if err != nil { - log.Fatalf("Error occurred in DeleteUser: %v", err) + t.Errorf("Error occurred in DeleteUser: %v", err) } user, err := dao.GetUser(*currentUser) if err != nil { - log.Fatalf("Error occurred in GetUser: %v", err) + t.Errorf("Error occurred in GetUser: %v", err) + } + if user != nil { + t.Error("user is not nil after deletion, user: %+v", user) } - fmt.Println(user) - //Output: - // } diff --git a/utils/registry_utils.go b/utils/registry_utils.go index 22e1fe455..13f989a2e 100644 --- a/utils/registry_utils.go +++ b/utils/registry_utils.go @@ -55,9 +55,9 @@ func HttpGet(url, sessionId, username, password string) ([]byte, error) { return nil, err } defer response.Body.Close() - if response.StatusCode == 200 { + if response.StatusCode == http.StatusOK { return result, nil - } else if response.StatusCode == 401 { + } else if response.StatusCode == http.StatusUnauthorized { authenticate := response.Header.Get("WWW-Authenticate") str := strings.Split(authenticate, " ")[1] beego.Trace("url: " + url) @@ -106,7 +106,7 @@ func HttpGet(url, sessionId, username, password string) ([]byte, error) { if err != nil { return nil, err } - if response.StatusCode == 200 { + if response.StatusCode == http.StatusOK { tt := make(map[string]string) json.Unmarshal(result, &tt) request, err = http.NewRequest("GET", url, nil) diff --git a/views/reset-password-mail.tpl b/views/reset-password-mail.tpl index 35b9c6976..e79cdfddb 100644 --- a/views/reset-password-mail.tpl +++ b/views/reset-password-mail.tpl @@ -16,6 +16,6 @@

{{.Hint}}:

- {{.Url}}/resetPassword?q={{.Uuid}} + {{.Url}}/resetPassword?reset_uuid={{.Uuid}} \ No newline at end of file