Merge pull request #3 from reasonerjt/master

sync code from personal repo
This commit is contained in:
reasonerjt 2016-02-24 14:40:16 +08:00
commit 2bdf12e2b4
29 changed files with 485 additions and 411 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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()

View File

@ -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
}
}

View File

@ -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")

View File

@ -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)

View File

@ -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
}
}

View File

@ -1,9 +0,0 @@
appname = harbor
runmode = dev
[lang]
types = en-US|zh-CN
names = en-US|zh-CN
[dev]
httpport = 80

View File

@ -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-----

View File

@ -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
}
}
}

View File

@ -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

View File

@ -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() {

View File

@ -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")
}
}

View File

@ -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()

View File

@ -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 `

View File

@ -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)
}

View File

@ -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
}

12
main.go
View File

@ -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()
}

View File

@ -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
}

View File

@ -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)

View File

@ -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)

View File

@ -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){

View File

@ -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", *dbIp)
os.Setenv("MYSQL_PORT_3306_TCP_PORT", *dbPort)
os.Setenv("MYSQL_USR", *dbUser)
os.Setenv("MYSQL_PWD", *dbPassword)
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())
}
}
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)
}
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)
}
}
for _, u := range users {
fmt.Println(u.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,35 +355,32 @@ 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 {
@ -358,89 +391,86 @@ func getProjectRole(projectId int64) []models.Role {
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 {
@ -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:
//<nil>
}

View File

@ -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)

View File

@ -16,6 +16,6 @@
<html>
<body>
<p>{{.Hint}}:</p>
<a href="{{.Url}}/resetPassword?q={{.Uuid}}">{{.Url}}/resetPassword?q={{.Uuid}}</a>
<a href="{{.Url}}/resetPassword?reset_uuid={{.Uuid}}">{{.Url}}/resetPassword?reset_uuid={{.Uuid}}</a>
</body>
</html>