From be6bf2ab226102782b6d04a95933b54c59c33c28 Mon Sep 17 00:00:00 2001 From: wemeya Date: Tue, 10 May 2016 15:10:19 +0800 Subject: [PATCH 01/29] add statistic api for projects and repos --- Deploy/config/registry/root.crt | 46 +++++++--- Deploy/config/ui/private_key.pem | 62 ++++++++++--- Deploy/harbor.cfg | 2 +- api/statistic.go | 146 +++++++++++++++++++++++++++++++ ui/router.go | 1 + 5 files changed, 230 insertions(+), 27 deletions(-) create mode 100644 api/statistic.go diff --git a/Deploy/config/registry/root.crt b/Deploy/config/registry/root.crt index 326d8080a..71ef6787f 100644 --- a/Deploy/config/registry/root.crt +++ b/Deploy/config/registry/root.crt @@ -1,15 +1,35 @@ -----BEGIN CERTIFICATE----- -MIICWDCCAcGgAwIBAgIJAN1nLuloDeHNMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQwHhcNMTYwMTI3MDQyMDM1WhcNNDMwNjE0MDQyMDM1WjBF -MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 -ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB -gQClak/4HO7EeLU0w/BhtVENPLOqU0AP2QjVUdg1qhNiDWVrbWx9KYHqz5Kn0n2+ -fxdZo3o7ZY5/2+hhgkKh1z6Kge9XGgune6z4fx2J/X2Se8WsGeQUTiND8ngSnsCA -NtYFwW50SbUZPtyf5XjAfKRofZem51OxbxzN3217L/ubKwIDAQABo1AwTjAdBgNV -HQ4EFgQU5EG2VrB3I6G/TudUpz+kBgQXSvYwHwYDVR0jBBgwFoAU5EG2VrB3I6G/ -TudUpz+kBgQXSvYwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQAx+2eo -oOm0YNy9KQ81+7GQkKVWoPQXjAGGgZuZj8WCFepYqUSJ4q5qbuVCY8WbGcHVk2Rx -Jg1XDCmMjBgYP6S0ikezBRqSmNA3G6oFiydTKBfPs6RNalsB0C78Xk5l5+PIyd2R -jFKOKoMpkjwfeJv2j64WNGoBgqj7XRBoJ11a4g== +MIIGBzCCA++gAwIBAgIJANjBN67MD5SgMA0GCSqGSIb3DQEBCwUAMIGZMQswCQYD +VQQGEwJDTjEOMAwGA1UECAwFU3RhdGUxCzAJBgNVBAcMAkNOMRUwEwYDVQQKDAxv +cmdhbml6YXRpb24xHDAaBgNVBAsME29yZ2FuaXphdGlvbmFsIHVuaXQxFDASBgNV +BAMMC2V4YW1wbGUuY29tMSIwIAYJKoZIhvcNAQkBFhNleGFtcGxlQGV4YW1wbGUu +Y29tMB4XDTE2MDUxMDA0MTMxM1oXDTI2MDUwODA0MTMxM1owgZkxCzAJBgNVBAYT +AkNOMQ4wDAYDVQQIDAVTdGF0ZTELMAkGA1UEBwwCQ04xFTATBgNVBAoMDG9yZ2Fu +aXphdGlvbjEcMBoGA1UECwwTb3JnYW5pemF0aW9uYWwgdW5pdDEUMBIGA1UEAwwL +ZXhhbXBsZS5jb20xIjAgBgkqhkiG9w0BCQEWE2V4YW1wbGVAZXhhbXBsZS5jb20w +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVSMUP/IR3iGdM4WrvuWno +Jy+mjOV/Qcte8gK92ClKd5zObAlo6/hn8ZMTeub76A9i39QN8GlQDFMtfv29EpLn +XXoVvLIwH4olycSdrye0ustOke/KT2RHAl3cVi5Zau0rfnb6h5kPQFFgjHsFdsLi +KIOBru976pJh3qxXq2xHIbmHvqLLEGuvt2WKXiRyz9ex6zbc/RTQhesJIA/N73Xo +9m5TfKOimuTedHYuGwS9XAHdr0W+EZl39keaPemrJz5QcebwwZPApuGwe0We8koL +0W1b2Z1a/gUdjcE++RVDOpHCupB/MltB+FSBJKd6LIbkjV1AC+T3NB3CzDPUP/Ep +bjk4wJqGOmMS+/mZbVu9lybrem7V0Wc03DEQyjZztpBcQ6MFbVw3pIbp3fAWhyDJ +N1y+i0O1Llcybpje5P3fQ0ioYc3hF61Wj3bAAx7ddPmrmtVGgisfvcTIRjNLGylM +qObhRjPPvky03x2jtwTnPX74gowuqq70sZHjfqpmXrjpJi9RMEJz30dxW6gy9Mn+ +MOTzwJ7iu3sm6XidaogMvMFrVlLfgIVLl+WfZJIv+i2by6TXfZ6/5OTvU4fzc1NZ +VeWBUSznmM/V72sWc/3AFgNibysv95OwDohqy91N9U73P6Q8H96hkDVHHhktHSL6 +s1OQau9XDgKS6xhZZsRxlwIDAQABo1AwTjAdBgNVHQ4EFgQUQl1pgU1b+rJMvLsQ +W1YednSAsDUwHwYDVR0jBBgwFoAUQl1pgU1b+rJMvLsQW1YednSAsDUwDAYDVR0T +BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAxCMLH/BhxzAGI2k8oBUXOaFXB+uo +2hrteE4glQw0nY959y7FEgKYBKKktWRqNBB/FlNSsrritfhWNK04tIHDQtUhP09m +2TD/0bxY++i+cyhqflHnyROkhAtcg1SBDhwkDMyEKnjzEe7t80Vq6d2sEBbq4PcA +Owl9Xj8elTt1g6aKP4Wt1V7ktZG+zAct+VPQtCnXCH2GAbkN8zqYKpCmzW0IBy0D +NFWKjsebXawOjUwMFu9MTDIwU3DvcCcrNj8k1palLPNNuyXqbsmencFjDRe2mZDU +lA2l4bpZ4G4HPSUJmhZHQ7eq9CYr5goS+kI36n5Uvg2TDDQQxXtfugRkI1qqxGlU +w+qc5BeQqkBior/dI/70+z0ith8/qZZ4U+y7eYY2lzIaNAOn2YLIdxkjF4YxIbSu +kV+Flxa4pFookeLvucZP1v3yW9VdHwClRGD4S4yiGC4j5uG8kcyRssH+iwdTm4Bl +0PSYiseeb0xlDaZMMq4K1IRvPLZ4PBKe+I6db8TIsTQjLIx8cUKaMdJlBUVLnmVG +uKKxdNz0OBUykEMAltHSagp/QqmVCED/q+Y1dsR2c2jy48dKl0mNRSTxMyaO1DTA +Fuzq0uQJetQdgwEdnoU0nabDk56vP686g4rJR8N6r822JxIfpE6ZLasgBX9P4jJS +rbSyDwCgpBd5p2g= -----END CERTIFICATE----- diff --git a/Deploy/config/ui/private_key.pem b/Deploy/config/ui/private_key.pem index 6c68cacb3..fb3d973fe 100644 --- a/Deploy/config/ui/private_key.pem +++ b/Deploy/config/ui/private_key.pem @@ -1,15 +1,51 @@ -----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 +MIIJKgIBAAKCAgEA1UjFD/yEd4hnTOFq77lp6Ccvpozlf0HLXvICvdgpSneczmwJ +aOv4Z/GTE3rm++gPYt/UDfBpUAxTLX79vRKS5116FbyyMB+KJcnEna8ntLrLTpHv +yk9kRwJd3FYuWWrtK352+oeZD0BRYIx7BXbC4iiDga7ve+qSYd6sV6tsRyG5h76i +yxBrr7dlil4kcs/Xses23P0U0IXrCSAPze916PZuU3yjoprk3nR2LhsEvVwB3a9F +vhGZd/ZHmj3pqyc+UHHm8MGTwKbhsHtFnvJKC9FtW9mdWv4FHY3BPvkVQzqRwrqQ +fzJbQfhUgSSneiyG5I1dQAvk9zQdwswz1D/xKW45OMCahjpjEvv5mW1bvZcm63pu +1dFnNNwxEMo2c7aQXEOjBW1cN6SG6d3wFocgyTdcvotDtS5XMm6Y3uT930NIqGHN +4RetVo92wAMe3XT5q5rVRoIrH73EyEYzSxspTKjm4UYzz75MtN8do7cE5z1++IKM +Lqqu9LGR436qZl646SYvUTBCc99HcVuoMvTJ/jDk88Ce4rt7Jul4nWqIDLzBa1ZS +34CFS5fln2SSL/otm8uk132ev+Tk71OH83NTWVXlgVEs55jP1e9rFnP9wBYDYm8r +L/eTsA6IasvdTfVO9z+kPB/eoZA1Rx4ZLR0i+rNTkGrvVw4CkusYWWbEcZcCAwEA +AQKCAgEAh6+k1pfCOj1H4owhuOKPMscDNIS8V+omlH+IKPiExEA2PMhUcDB2tsHj +3Ge63RVz/GYDBN8mUGuW2wHIMOnJFXHNgliqT50xCPtEn0BYFU0knBaRo3ZAiEBE +MDGPiQlSWvI4hQeQ4zf6zV5xwTcdoj099FmzN3UyrRq5L4j5+ILHAknQTTlkGMSm +z5E2xOffA+xs2cgT3tjjfsmr5EpsC8oCxBAuFftOkQssSAaeTE1lTn/78YBGzx+Z +y9GJf34W0Zy03AN6mPxR5jF2SDlBzCTu2pkl10Z1QKj3ALX7xepT4rtHw/PoRJ7U +O9hyx3HeWzZn1Z/7iRzZthys+GG5bIUhEwpjU1j2cbVVYIOkZhPilmhqREzGSJcQ +szs6TKjD7UL2W0+fhQ7uknheQ0mqBwDPrj9gN3gqK9UTHSZi2u1rA4AUXXCRu5v0 +wlU9gQ4fD0t9HO2J+QDSZ5Qz58zj+TE/Ohz8BFNyIGBQGIv4eJ8eRFydZDSRYif4 +VvPox7OxDBw4Ug8gwEOQhh2NQbl2ocFZcevYVajUDbWmoh2omoPdVI8L0Vm8aRxt +hFvHSDqfaEVId6LsH5mcng8lVeZsg4R+yx38+JUgafCSXS7+KHN2+XeiAkY+L8Ik +3reQ3iSaTvEb34E2/0IkRbtZyn5NkjDvYU5DWHeexxVjfBPPsukCggEBAPmpeJ1+ +PlzJN3HX1m/GuAcR7WXt1Itm5OnZlNF47jj3nQVo/2FxPxvivv6tqHOg8Jmo6nzj +S6EqyUbYB/VkbREpY8y+tEsgctakC9uOOIRBygK8olpaB1ncuoApXRWPsH73Ik5Q +s/W3Kf/8tQDNom64wTAKOBuIGLSq9A1pyFS97lsiEPMzilUoHywomIE76hcyTCVL +uXzZmPzRlOjvmW6Z9qHMSRtAI5NOuRIQ1vvXggnIuBB8hxmkQdESiu4cDQoJ61Tv ++PVA12R/G6kWmGaLvB8Vo0DYfWfFgExYDuYhE2ubsAEP2OTQmOQG+UPQKwPKv2/q +2xk2mp3tMbXbGbsCggEBANqy4h0djzr/6Iu0BsJJmreEElSHaS6zt9whkntUzWpj +A8LnmmXqJNT6PksuDAGyf3/TmmTZ6GXZJQXkDtUfiDZrq38JFkJRGJDUiB4cODzp +CuhZ66Dv+HmlaA9w4ZIqzHw2JwrC1Ys6s1N+SBSwCpI6LOpfbRHjxinrHG+HV3SW +MNlhUdoMzDM6isp0UOtF2dfRvY/gyspKM6XnZsrIBFBJI1JcgCvM0r0iDfYJiqSh +pKYPGstUqnYjEOUgv38kEUoq1Sf8Xxg2+BoNYJTQApuIsFxIG6RWuI8qzTHec6cV +QjMHP325itNLbuTRh5TGWMwuRDoEbKlSJtrUdbfHC9UCggEBAO1cdlQmBlxo4dHW +hwVWRPhTzwStjPnMJa8/MgHFm5eFsz/Fh6e452s3tKalrBXi2Vz9/5Ik926PIzW7 +hjWD+T3rv/qVBQy4GPaAmNVw7cKwWcMoXKLSHVMOTDI1IU6ygfb0NyWGDNJ8Be5e +8CeHWfsypFlsHdPvHK4IKmfmPpRyzv7N8JeIVOiJcLmnDvcvY2wSYdrDl+JfbthO +2ehsg89nidhiRM8nt6sBmWrXn81oIzXyIy1pd3ildf20R2oCOVNmAtuKG4Pw1dey +ETY9ST+VcpGLHN819GSInWX4ApJAuBoCtt8LlgZVXEbPaoVSkNLWHBPnkc7y3yVu +sWhYmqkCggEBAIi4qkk/cIqW779exZbywumVhIwZt3T936SbzGKT6nNnATP47Hpo +Paxz4TvIxrLM745vMCd6XyJE9TNQlsFAHDzBZQ5fFO5SmoP4ijwgsjvKCQqnJHqR +awpJkNuOW0awwPOqOxAsK6oGAZPh75gXUhSGkAvZqmsztXABTt6egtsdBd7wS2aA +96vTHm9g9jGPkpesxNBM3RpH9y/xkT6WerPidVWJBIvdWaXpw0acQnOXpkI2US7q +eEKwu2Ay7+TBHJn8WxPLX3vY6ZQH5uhBfk/TzUVzwuwjVvAR9wQFKNI8pQ0Xq+ai +dxqPHv2nzBYDRgInrnmCyJe2BxppFkrVAh0CggEAS4LpuAkzMrcn4bE4QNn1kKHP +HfYs462ueCI0M9rHI45S4st1MLOtAr+2IZWfd0PApcI4oEDGVO3XbOzMrxKxWS1m +kv62kTqcgQnXi3kZEGeduzjst2lrrKqYsuTMlgnkwPrvM+PHxmUkqsOoBOKbpGNf +06Kgy6h/5Ccu/nva3d5iL4AtfuWiMCY1w6WwPjIUp/oRvJXkN25X5DV+G34AIicy +GIoeb3PPbpsBgKQk0gMy/uTbE96+woSTGubL5ck1UxvbptAy0UTslZUPh2aZ7Rx/ +CllGWHa3eM8nS0/Q1FdgbzLOT9EiZrAlTziYV0SDBU9fkvh+7WWIkn61F19TjQ== -----END RSA PRIVATE KEY----- diff --git a/Deploy/harbor.cfg b/Deploy/harbor.cfg index bd949cea5..1a59f9578 100644 --- a/Deploy/harbor.cfg +++ b/Deploy/harbor.cfg @@ -2,7 +2,7 @@ #The IP address or hostname to access admin UI and registry service. #DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients. -hostname = reg.mydomain.com +hostname = localhost #The protocol for accessing the UI and token/notification service, by default it is http. #It can be set to https if ssl is enabled on nginx. diff --git a/api/statistic.go b/api/statistic.go new file mode 100644 index 000000000..5612fcd93 --- /dev/null +++ b/api/statistic.go @@ -0,0 +1,146 @@ +/* + 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 api + +import ( + "net/http" + "os" + + "github.com/vmware/harbor/dao" + "github.com/vmware/harbor/models" + svc_utils "github.com/vmware/harbor/service/utils" + "github.com/vmware/harbor/utils/log" + "github.com/vmware/harbor/utils/registry" + "github.com/vmware/harbor/utils/registry/auth" +) + +type StatisticAPI struct { + BaseAPI + userID int + username string + registry *registry.Registry +} + +//Prepare validates the URL and the user +func (s *StatisticAPI) Prepare() { + userID, ok := s.GetSession("userId").(int) + if !ok { + s.userID = dao.NonExistUserID + } else { + s.userID = userID + log.Debug("userID is xxx", userID) + } + username, ok := s.GetSession("username").(string) + if !ok { + log.Warning("failed to get username from session") + s.username = "" + } else { + s.username = username + log.Debug("username is xxx", username) + } + + var client *http.Client + + //no session, initialize a standard auth handler + if s.userID == dao.NonExistUserID && len(s.username) == 0 { + username, password, _ := s.Ctx.Request.BasicAuth() + + credential := auth.NewBasicAuthCredential(username, password) + client = registry.NewClientStandardAuthHandlerEmbeded(credential) + log.Debug("initializing standard auth handler") + + } else { + // session works, initialize a username auth handler + username := s.username + if len(username) == 0 { + user, err := dao.GetUser(models.User{ + UserID: s.userID, + }) + if err != nil { + log.Errorf("error occurred whiling geting user for initializing a username auth handler: %v", err) + return + } + + username = user.Username + } + + client = registry.NewClientUsernameAuthHandlerEmbeded(username) + log.Debug("initializing username auth handler: %s", username) + } + + endpoint := os.Getenv("REGISTRY_URL") + r, err := registry.New(endpoint, client) + if err != nil { + log.Fatalf("error occurred while initializing auth handler for repository API: %v", err) + } + + s.registry = r +} + +// Get total projects and repos of the user +func (s *StatisticAPI) Get() { + queryProject := models.Project{UserID: s.userID} + projectList, err := dao.QueryProject(queryProject) + var projectArr [6]int + if err != nil { + log.Errorf("Error occured in QueryProject, error: %v", err) + s.CustomAbort(http.StatusInternalServerError, "Internal error.") + } + log.Debug("projectList xxx ", projectList) + isAdmin, _ := dao.IsAdminRole(s.userID) + for i := 0; i < len(projectList); i++ { + if isProjectAdmin(s.userID, projectList[i].ProjectID) { + projectArr[0] += 1 + projectArr[1] += s.GetRepos(projectList[i].ProjectID) + } + if projectList[i].Public == 1 { + projectArr[2] += 1 + projectArr[3] += s.GetRepos(projectList[i].ProjectID) + } + if isAdmin { + projectArr[5] += s.GetRepos(projectList[i].ProjectID) + } + } + if isAdmin { + projectArr[4] = len(projectList) + } + s.Data["json"] = projectArr + s.ServeJSON() +} + +func (s *StatisticAPI) GetRepos(projectID int64) int { + p, err := dao.GetProjectByID(projectID) + if err != nil { + log.Errorf("Error occurred in GetProjectById, error: %v", err) + s.CustomAbort(http.StatusInternalServerError, "Internal error.") + } + if p == nil { + log.Warningf("Project with Id: %d does not exist", projectID) + s.RenderError(http.StatusNotFound, "") + return 0 + } + if p.Public == 0 && !checkProjectPermission(s.userID, projectID) { + s.RenderError(http.StatusForbidden, "") + return 0 + } + + repoList, err := svc_utils.GetRepoFromCache() + if err != nil { + log.Errorf("Failed to get repo from cache, error: %v", err) + s.RenderError(http.StatusInternalServerError, "internal sever error") + } + return len(repoList) +} diff --git a/ui/router.go b/ui/router.go index 401745410..1218424c2 100644 --- a/ui/router.go +++ b/ui/router.go @@ -54,6 +54,7 @@ func initRouters() { beego.Router("/api/search", &api.SearchAPI{}) beego.Router("/api/projects/:pid/members/?:mid", &api.ProjectMemberAPI{}) beego.Router("/api/projects/?:id", &api.ProjectAPI{}) + beego.Router("/api/statistics", &api.StatisticAPI{}) beego.Router("/api/projects/:id/logs/filter", &api.ProjectAPI{}, "post:FilterAccessLog") beego.Router("/api/users", &api.UserAPI{}) beego.Router("/api/users/?:id", &api.UserAPI{}) From 7aa482a5c6e63645b903636ff67cca9b5811b9d5 Mon Sep 17 00:00:00 2001 From: wemeya Date: Tue, 10 May 2016 15:23:47 +0800 Subject: [PATCH 02/29] revoke unnecessary changes --- Deploy/config/registry/root.crt | 46 +++++++----------------- Deploy/config/ui/private_key.pem | 62 +++++++------------------------- Deploy/harbor.cfg | 2 +- 3 files changed, 27 insertions(+), 83 deletions(-) diff --git a/Deploy/config/registry/root.crt b/Deploy/config/registry/root.crt index 71ef6787f..326d8080a 100644 --- a/Deploy/config/registry/root.crt +++ b/Deploy/config/registry/root.crt @@ -1,35 +1,15 @@ -----BEGIN CERTIFICATE----- -MIIGBzCCA++gAwIBAgIJANjBN67MD5SgMA0GCSqGSIb3DQEBCwUAMIGZMQswCQYD -VQQGEwJDTjEOMAwGA1UECAwFU3RhdGUxCzAJBgNVBAcMAkNOMRUwEwYDVQQKDAxv -cmdhbml6YXRpb24xHDAaBgNVBAsME29yZ2FuaXphdGlvbmFsIHVuaXQxFDASBgNV -BAMMC2V4YW1wbGUuY29tMSIwIAYJKoZIhvcNAQkBFhNleGFtcGxlQGV4YW1wbGUu -Y29tMB4XDTE2MDUxMDA0MTMxM1oXDTI2MDUwODA0MTMxM1owgZkxCzAJBgNVBAYT -AkNOMQ4wDAYDVQQIDAVTdGF0ZTELMAkGA1UEBwwCQ04xFTATBgNVBAoMDG9yZ2Fu -aXphdGlvbjEcMBoGA1UECwwTb3JnYW5pemF0aW9uYWwgdW5pdDEUMBIGA1UEAwwL -ZXhhbXBsZS5jb20xIjAgBgkqhkiG9w0BCQEWE2V4YW1wbGVAZXhhbXBsZS5jb20w -ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVSMUP/IR3iGdM4WrvuWno -Jy+mjOV/Qcte8gK92ClKd5zObAlo6/hn8ZMTeub76A9i39QN8GlQDFMtfv29EpLn -XXoVvLIwH4olycSdrye0ustOke/KT2RHAl3cVi5Zau0rfnb6h5kPQFFgjHsFdsLi -KIOBru976pJh3qxXq2xHIbmHvqLLEGuvt2WKXiRyz9ex6zbc/RTQhesJIA/N73Xo -9m5TfKOimuTedHYuGwS9XAHdr0W+EZl39keaPemrJz5QcebwwZPApuGwe0We8koL -0W1b2Z1a/gUdjcE++RVDOpHCupB/MltB+FSBJKd6LIbkjV1AC+T3NB3CzDPUP/Ep -bjk4wJqGOmMS+/mZbVu9lybrem7V0Wc03DEQyjZztpBcQ6MFbVw3pIbp3fAWhyDJ -N1y+i0O1Llcybpje5P3fQ0ioYc3hF61Wj3bAAx7ddPmrmtVGgisfvcTIRjNLGylM -qObhRjPPvky03x2jtwTnPX74gowuqq70sZHjfqpmXrjpJi9RMEJz30dxW6gy9Mn+ -MOTzwJ7iu3sm6XidaogMvMFrVlLfgIVLl+WfZJIv+i2by6TXfZ6/5OTvU4fzc1NZ -VeWBUSznmM/V72sWc/3AFgNibysv95OwDohqy91N9U73P6Q8H96hkDVHHhktHSL6 -s1OQau9XDgKS6xhZZsRxlwIDAQABo1AwTjAdBgNVHQ4EFgQUQl1pgU1b+rJMvLsQ -W1YednSAsDUwHwYDVR0jBBgwFoAUQl1pgU1b+rJMvLsQW1YednSAsDUwDAYDVR0T -BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAxCMLH/BhxzAGI2k8oBUXOaFXB+uo -2hrteE4glQw0nY959y7FEgKYBKKktWRqNBB/FlNSsrritfhWNK04tIHDQtUhP09m -2TD/0bxY++i+cyhqflHnyROkhAtcg1SBDhwkDMyEKnjzEe7t80Vq6d2sEBbq4PcA -Owl9Xj8elTt1g6aKP4Wt1V7ktZG+zAct+VPQtCnXCH2GAbkN8zqYKpCmzW0IBy0D -NFWKjsebXawOjUwMFu9MTDIwU3DvcCcrNj8k1palLPNNuyXqbsmencFjDRe2mZDU -lA2l4bpZ4G4HPSUJmhZHQ7eq9CYr5goS+kI36n5Uvg2TDDQQxXtfugRkI1qqxGlU -w+qc5BeQqkBior/dI/70+z0ith8/qZZ4U+y7eYY2lzIaNAOn2YLIdxkjF4YxIbSu -kV+Flxa4pFookeLvucZP1v3yW9VdHwClRGD4S4yiGC4j5uG8kcyRssH+iwdTm4Bl -0PSYiseeb0xlDaZMMq4K1IRvPLZ4PBKe+I6db8TIsTQjLIx8cUKaMdJlBUVLnmVG -uKKxdNz0OBUykEMAltHSagp/QqmVCED/q+Y1dsR2c2jy48dKl0mNRSTxMyaO1DTA -Fuzq0uQJetQdgwEdnoU0nabDk56vP686g4rJR8N6r822JxIfpE6ZLasgBX9P4jJS -rbSyDwCgpBd5p2g= +MIICWDCCAcGgAwIBAgIJAN1nLuloDeHNMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTYwMTI3MDQyMDM1WhcNNDMwNjE0MDQyMDM1WjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB +gQClak/4HO7EeLU0w/BhtVENPLOqU0AP2QjVUdg1qhNiDWVrbWx9KYHqz5Kn0n2+ +fxdZo3o7ZY5/2+hhgkKh1z6Kge9XGgune6z4fx2J/X2Se8WsGeQUTiND8ngSnsCA +NtYFwW50SbUZPtyf5XjAfKRofZem51OxbxzN3217L/ubKwIDAQABo1AwTjAdBgNV +HQ4EFgQU5EG2VrB3I6G/TudUpz+kBgQXSvYwHwYDVR0jBBgwFoAU5EG2VrB3I6G/ +TudUpz+kBgQXSvYwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQAx+2eo +oOm0YNy9KQ81+7GQkKVWoPQXjAGGgZuZj8WCFepYqUSJ4q5qbuVCY8WbGcHVk2Rx +Jg1XDCmMjBgYP6S0ikezBRqSmNA3G6oFiydTKBfPs6RNalsB0C78Xk5l5+PIyd2R +jFKOKoMpkjwfeJv2j64WNGoBgqj7XRBoJ11a4g== -----END CERTIFICATE----- diff --git a/Deploy/config/ui/private_key.pem b/Deploy/config/ui/private_key.pem index fb3d973fe..6c68cacb3 100644 --- a/Deploy/config/ui/private_key.pem +++ b/Deploy/config/ui/private_key.pem @@ -1,51 +1,15 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/Deploy/harbor.cfg b/Deploy/harbor.cfg index 1a59f9578..bd949cea5 100644 --- a/Deploy/harbor.cfg +++ b/Deploy/harbor.cfg @@ -2,7 +2,7 @@ #The IP address or hostname to access admin UI and registry service. #DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients. -hostname = localhost +hostname = reg.mydomain.com #The protocol for accessing the UI and token/notification service, by default it is http. #It can be set to https if ssl is enabled on nginx. From 8502d3da1be4d365820c0e3b19691c6cbe16ee3d Mon Sep 17 00:00:00 2001 From: wemeya Date: Wed, 11 May 2016 15:54:26 +0800 Subject: [PATCH 03/29] change api for statistics --- api/project.go | 4 +- api/statistic.go | 115 +++++++++++++++------------------------------- dao/project.go | 2 +- models/project.go | 2 + 4 files changed, 44 insertions(+), 79 deletions(-) diff --git a/api/project.go b/api/project.go index 993cc9ad7..afe4783be 100644 --- a/api/project.go +++ b/api/project.go @@ -126,10 +126,12 @@ func (p *ProjectAPI) Get() { log.Errorf("Error occurred in QueryProject, error: %v", err) p.CustomAbort(http.StatusInternalServerError, "Internal error.") } + sa := &StatisticAPI{userID: p.userID, username: ""} for i := 0; i < len(projectList); i++ { - if isProjectAdmin(p.userID, projectList[i].ProjectID) { + if projectList[i].Role == 1 { projectList[i].Togglable = true } + projectList[i].Repos = sa.GetReposByProject(projectList[i].Name, false) } p.Data["json"] = projectList p.ServeJSON() diff --git a/api/statistic.go b/api/statistic.go index 5612fcd93..05b095679 100644 --- a/api/statistic.go +++ b/api/statistic.go @@ -17,21 +17,19 @@ package api import ( "net/http" - "os" + "strings" "github.com/vmware/harbor/dao" "github.com/vmware/harbor/models" svc_utils "github.com/vmware/harbor/service/utils" "github.com/vmware/harbor/utils/log" - "github.com/vmware/harbor/utils/registry" - "github.com/vmware/harbor/utils/registry/auth" ) +// StatisticAPI handles request to /api/statistics/ type StatisticAPI struct { BaseAPI userID int username string - registry *registry.Registry } //Prepare validates the URL and the user @@ -41,7 +39,6 @@ func (s *StatisticAPI) Prepare() { s.userID = dao.NonExistUserID } else { s.userID = userID - log.Debug("userID is xxx", userID) } username, ok := s.GetSession("username").(string) if !ok { @@ -49,98 +46,62 @@ func (s *StatisticAPI) Prepare() { s.username = "" } else { s.username = username - log.Debug("username is xxx", username) } - - var client *http.Client - - //no session, initialize a standard auth handler - if s.userID == dao.NonExistUserID && len(s.username) == 0 { - username, password, _ := s.Ctx.Request.BasicAuth() - - credential := auth.NewBasicAuthCredential(username, password) - client = registry.NewClientStandardAuthHandlerEmbeded(credential) - log.Debug("initializing standard auth handler") - - } else { - // session works, initialize a username auth handler - username := s.username - if len(username) == 0 { - user, err := dao.GetUser(models.User{ - UserID: s.userID, - }) - if err != nil { - log.Errorf("error occurred whiling geting user for initializing a username auth handler: %v", err) - return - } - - username = user.Username - } - - client = registry.NewClientUsernameAuthHandlerEmbeded(username) - log.Debug("initializing username auth handler: %s", username) - } - - endpoint := os.Getenv("REGISTRY_URL") - r, err := registry.New(endpoint, client) - if err != nil { - log.Fatalf("error occurred while initializing auth handler for repository API: %v", err) - } - - s.registry = r } // Get total projects and repos of the user func (s *StatisticAPI) Get() { queryProject := models.Project{UserID: s.userID} projectList, err := dao.QueryProject(queryProject) - var projectArr [6]int + proMap := map[string]int{} if err != nil { log.Errorf("Error occured in QueryProject, error: %v", err) s.CustomAbort(http.StatusInternalServerError, "Internal error.") } - log.Debug("projectList xxx ", projectList) - isAdmin, _ := dao.IsAdminRole(s.userID) - for i := 0; i < len(projectList); i++ { - if isProjectAdmin(s.userID, projectList[i].ProjectID) { - projectArr[0] += 1 - projectArr[1] += s.GetRepos(projectList[i].ProjectID) - } - if projectList[i].Public == 1 { - projectArr[2] += 1 - projectArr[3] += s.GetRepos(projectList[i].ProjectID) - } - if isAdmin { - projectArr[5] += s.GetRepos(projectList[i].ProjectID) - } + isAdmin, err0 := dao.IsAdminRole(s.userID) + if err0 != nil { + log.Errorf("Error occured in check admin, error: %v", err0) + s.CustomAbort(http.StatusInternalServerError, "Internal error.") } if isAdmin { - projectArr[4] = len(projectList) + proMap["total_project"] = len(projectList) } - s.Data["json"] = projectArr + for i := 0; i < len(projectList); i++ { + if projectList[i].Role == 1 || projectList[i].Role == 2 { + proMap["my_project"]++ + proMap["my_repos"] += s.GetReposByProject(projectList[i].Name, false) + } + if projectList[i].Public == 1 { + proMap["public_project"]++ + proMap["public_repos"] += s.GetReposByProject(projectList[i].Name, false) + } + if isAdmin { + proMap["total_repos"] = s.GetReposByProject(projectList[i].Name, true) + } + } + log.Debug(projectList) + s.Data["json"] = proMap s.ServeJSON() } -func (s *StatisticAPI) GetRepos(projectID int64) int { - p, err := dao.GetProjectByID(projectID) - if err != nil { - log.Errorf("Error occurred in GetProjectById, error: %v", err) - s.CustomAbort(http.StatusInternalServerError, "Internal error.") - } - if p == nil { - log.Warningf("Project with Id: %d does not exist", projectID) - s.RenderError(http.StatusNotFound, "") - return 0 - } - if p.Public == 0 && !checkProjectPermission(s.userID, projectID) { - s.RenderError(http.StatusForbidden, "") - return 0 - } - +//return repo numbers of specified project +func (s *StatisticAPI) GetReposByProject(projectName string, isAdmin bool) int { repoList, err := svc_utils.GetRepoFromCache() if err != nil { log.Errorf("Failed to get repo from cache, error: %v", err) s.RenderError(http.StatusInternalServerError, "internal sever error") } - return len(repoList) + if isAdmin { + return len(repoList) + } + var resp []string + if len(projectName) > 0 { + for _, r := range repoList { + if strings.Contains(r, "/") && r[0:strings.LastIndex(r, "/")] == projectName { + resp = append(resp, r) + } + } + return len(resp) + } + return 0 } diff --git a/dao/project.go b/dao/project.go index 9eba4f78e..cb41e303c 100644 --- a/dao/project.go +++ b/dao/project.go @@ -84,7 +84,7 @@ func QueryProject(query models.Project) ([]models.Project, error) { o := orm.NewOrm() sql := `select distinct - p.project_id, p.owner_id, p.name,p.creation_time, p.update_time, p.public + p.project_id, p.owner_id, p.name,p.creation_time, p.update_time, p.public, pm.role role from project p left join project_member pm on p.project_id = pm.project_id where p.deleted = 0 ` diff --git a/models/project.go b/models/project.go index e240c609f..6fa9257d7 100644 --- a/models/project.go +++ b/models/project.go @@ -34,4 +34,6 @@ type Project struct { Togglable bool UpdateTime time.Time `orm:"update_time" json:"update_time"` + Role int `json:"RoleId"` + Repos int } From acb2d0252b1eb9326995992973a87af3a56f555f Mon Sep 17 00:00:00 2001 From: wemeya Date: Wed, 11 May 2016 16:05:35 +0800 Subject: [PATCH 04/29] change the comment of the function --- api/statistic.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/statistic.go b/api/statistic.go index 05b095679..cc2bfb259 100644 --- a/api/statistic.go +++ b/api/statistic.go @@ -84,7 +84,7 @@ func (s *StatisticAPI) Get() { s.ServeJSON() } -//return repo numbers of specified project +//GetReposByProject returns repo numbers of specified project func (s *StatisticAPI) GetReposByProject(projectName string, isAdmin bool) int { repoList, err := svc_utils.GetRepoFromCache() if err != nil { From f43d6dab189da789fb7e97e8544fe31e4c4175a9 Mon Sep 17 00:00:00 2001 From: wemeya Date: Thu, 12 May 2016 14:56:43 +0800 Subject: [PATCH 05/29] change api for statistics and project repo, roleid --- api/statistic.go | 1 - dao/project.go | 23 ++++++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/api/statistic.go b/api/statistic.go index cc2bfb259..9aeab1bcd 100644 --- a/api/statistic.go +++ b/api/statistic.go @@ -79,7 +79,6 @@ func (s *StatisticAPI) Get() { proMap["total_repos"] = s.GetReposByProject(projectList[i].Name, true) } } - log.Debug(projectList) s.Data["json"] = proMap s.ServeJSON() } diff --git a/dao/project.go b/dao/project.go index 5c53a0f26..cc73ff841 100644 --- a/dao/project.go +++ b/dao/project.go @@ -84,19 +84,19 @@ func QueryProject(query models.Project) ([]models.Project, error) { o := orm.NewOrm() sql := `select distinct - p.project_id, p.owner_id, p.name,p.creation_time, p.update_time, p.public, pm.role role - from project p - left join project_member pm on p.project_id = pm.project_id - where p.deleted = 0 ` - + p.project_id, p.owner_id, p.name,p.creation_time, p.update_time, p.public` queryParam := make([]interface{}, 1) - + isAdmin, _ := IsAdminRole(query.UserID) if query.Public == 1 { - sql += ` and p.public = ?` + sql += ` from project p where p.deleted = 0 and p.public = ?` queryParam = append(queryParam, query.Public) - } else if isAdmin, _ := IsAdminRole(query.UserID); isAdmin == false { - sql += ` and (pm.user_id = ?) ` + } else if !isAdmin { + sql += `, pm.role role from project p + left join project_member pm on p.project_id = pm.project_id + where p.deleted = 0 and (pm.user_id = ?) ` queryParam = append(queryParam, query.UserID) + } else if isAdmin { + sql += ` from project p where p.deleted = 0 ` } if query.Name != "" { @@ -112,6 +112,11 @@ func QueryProject(query models.Project) ([]models.Project, error) { if err != nil { return nil, err } + if isAdmin { + for i := 0; i < len(r); i++ { + r[i].Role = 1 + } + } return r, nil } From 8c35e6ffa2d18991fca7b2f8e3595b29ec9a770c Mon Sep 17 00:00:00 2001 From: wemeya Date: Fri, 13 May 2016 22:45:30 +0800 Subject: [PATCH 06/29] change code for statistic and project repo_count, role_id api --- api/project.go | 5 ++--- api/statistic.go | 36 +++++++++++++++++++++--------------- dao/project.go | 16 +++++++++++----- models/project.go | 4 ++-- 4 files changed, 36 insertions(+), 25 deletions(-) diff --git a/api/project.go b/api/project.go index 35b089060..e14668e10 100644 --- a/api/project.go +++ b/api/project.go @@ -126,12 +126,11 @@ func (p *ProjectAPI) Get() { log.Errorf("Error occurred in QueryProject, error: %v", err) p.CustomAbort(http.StatusInternalServerError, "Internal error.") } - sa := &StatisticAPI{userID: p.userID, username: ""} for i := 0; i < len(projectList); i++ { - if projectList[i].Role == 1 { + if projectList[i].Role == models.PROJECTADMIN { projectList[i].Togglable = true } - projectList[i].Repos = sa.GetReposByProject(projectList[i].Name, false) + projectList[i].RepoCount = getRepoCountByProject(projectList[i].Name) } p.Data["json"] = projectList p.ServeJSON() diff --git a/api/statistic.go b/api/statistic.go index 9aeab1bcd..b16b5d875 100644 --- a/api/statistic.go +++ b/api/statistic.go @@ -64,34 +64,29 @@ func (s *StatisticAPI) Get() { s.CustomAbort(http.StatusInternalServerError, "Internal error.") } if isAdmin { - proMap["total_project"] = len(projectList) + proMap["total_project_count"] = len(projectList) + proMap["total_repo_count"] = getTotalRepoCount() } for i := 0; i < len(projectList); i++ { - if projectList[i].Role == 1 || projectList[i].Role == 2 { - proMap["my_project"]++ - proMap["my_repos"] += s.GetReposByProject(projectList[i].Name, false) + if projectList[i].Role == models.PROJECTADMIN || projectList[i].Role == models.DEVELOPER { + proMap["my_project_count"]++ + proMap["my_repo_count"] += getRepoCountByProject(projectList[i].Name) } if projectList[i].Public == 1 { - proMap["public_project"]++ - proMap["public_repos"] += s.GetReposByProject(projectList[i].Name, false) - } - if isAdmin { - proMap["total_repos"] = s.GetReposByProject(projectList[i].Name, true) + proMap["public_project_count"]++ + proMap["public_repo_count"] += getRepoCountByProject(projectList[i].Name) } } s.Data["json"] = proMap s.ServeJSON() } -//GetReposByProject returns repo numbers of specified project -func (s *StatisticAPI) GetReposByProject(projectName string, isAdmin bool) int { +//getReposByProject returns repo numbers of specified project +func getRepoCountByProject(projectName string) int { repoList, err := svc_utils.GetRepoFromCache() if err != nil { log.Errorf("Failed to get repo from cache, error: %v", err) - s.RenderError(http.StatusInternalServerError, "internal sever error") - } - if isAdmin { - return len(repoList) + return 0 } var resp []string if len(projectName) > 0 { @@ -104,3 +99,14 @@ func (s *StatisticAPI) GetReposByProject(projectName string, isAdmin bool) int { } return 0 } + +//getTotalRepoCount returns total repo count +func getTotalRepoCount() int { + repoList, err := svc_utils.GetRepoFromCache() + if err != nil { + log.Errorf("Failed to get repo from cache, error: %v", err) + return 0 + } + return len(repoList) + +} diff --git a/dao/project.go b/dao/project.go index cc73ff841..97ef37e14 100644 --- a/dao/project.go +++ b/dao/project.go @@ -86,19 +86,25 @@ func QueryProject(query models.Project) ([]models.Project, error) { sql := `select distinct p.project_id, p.owner_id, p.name,p.creation_time, p.update_time, p.public` queryParam := make([]interface{}, 1) - isAdmin, _ := IsAdminRole(query.UserID) + isAdmin, err := IsAdminRole(query.UserID) + if err != nil { + return nil, err + } + if query.Public == 1 { + //if the project is public sql += ` from project p where p.deleted = 0 and p.public = ?` queryParam = append(queryParam, query.Public) } else if !isAdmin { + //if the user is not admin, should join the project_member table to query his/her projects and role id sql += `, pm.role role from project p left join project_member pm on p.project_id = pm.project_id where p.deleted = 0 and (pm.user_id = ?) ` queryParam = append(queryParam, query.UserID) } else if isAdmin { + //if the user is admin, return all projects sql += ` from project p where p.deleted = 0 ` } - if query.Name != "" { sql += " and p.name like ? " queryParam = append(queryParam, query.Name) @@ -107,14 +113,14 @@ func QueryProject(query models.Project) ([]models.Project, error) { sql += " order by p.name " var r []models.Project - _, err := o.Raw(sql, queryParam).QueryRows(&r) + _, err0 := o.Raw(sql, queryParam).QueryRows(&r) - if err != nil { + if err0 != nil { return nil, err } if isAdmin { for i := 0; i < len(r); i++ { - r[i].Role = 1 + r[i].Role = models.PROJECTADMIN } } return r, nil diff --git a/models/project.go b/models/project.go index 6fa9257d7..2ebd5fc32 100644 --- a/models/project.go +++ b/models/project.go @@ -34,6 +34,6 @@ type Project struct { Togglable bool UpdateTime time.Time `orm:"update_time" json:"update_time"` - Role int `json:"RoleId"` - Repos int + Role int `json:"role_id"` + RepoCount int `json:"repo_count"` } From 85ce86df1abdc535c1171206e4be167ce7123f36 Mon Sep 17 00:00:00 2001 From: wemeya Date: Fri, 13 May 2016 15:28:26 +0800 Subject: [PATCH 07/29] change code of statistic api --- api/statistic.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/api/statistic.go b/api/statistic.go index b16b5d875..91f34c9c2 100644 --- a/api/statistic.go +++ b/api/statistic.go @@ -53,14 +53,14 @@ func (s *StatisticAPI) Prepare() { func (s *StatisticAPI) Get() { queryProject := models.Project{UserID: s.userID} projectList, err := dao.QueryProject(queryProject) - proMap := map[string]int{} if err != nil { log.Errorf("Error occured in QueryProject, error: %v", err) s.CustomAbort(http.StatusInternalServerError, "Internal error.") } - isAdmin, err0 := dao.IsAdminRole(s.userID) - if err0 != nil { - log.Errorf("Error occured in check admin, error: %v", err0) + proMap := map[string]int{} + isAdmin, err := dao.IsAdminRole(s.userID) + if err != nil { + log.Errorf("Error occured in check admin, error: %v", err) s.CustomAbort(http.StatusInternalServerError, "Internal error.") } if isAdmin { @@ -68,7 +68,8 @@ func (s *StatisticAPI) Get() { proMap["total_repo_count"] = getTotalRepoCount() } for i := 0; i < len(projectList); i++ { - if projectList[i].Role == models.PROJECTADMIN || projectList[i].Role == models.DEVELOPER { + if projectList[i].Role == models.PROJECTADMIN || projectList[i].Role == models.DEVELOPER || + projectList[i].Role == models.GUEST { proMap["my_project_count"]++ proMap["my_repo_count"] += getRepoCountByProject(projectList[i].Name) } @@ -88,14 +89,14 @@ func getRepoCountByProject(projectName string) int { log.Errorf("Failed to get repo from cache, error: %v", err) return 0 } - var resp []string + var resp int if len(projectName) > 0 { for _, r := range repoList { if strings.Contains(r, "/") && r[0:strings.LastIndex(r, "/")] == projectName { - resp = append(resp, r) + resp += 1 } } - return len(resp) + return resp } return 0 } From c5b1b86d891eba17e3ce02fb01cbb304e6767be1 Mon Sep 17 00:00:00 2001 From: wemeya Date: Fri, 13 May 2016 16:18:48 +0800 Subject: [PATCH 08/29] modify code where CI unpassed --- api/statistic.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/statistic.go b/api/statistic.go index 91f34c9c2..d594d2e2c 100644 --- a/api/statistic.go +++ b/api/statistic.go @@ -93,7 +93,7 @@ func getRepoCountByProject(projectName string) int { if len(projectName) > 0 { for _, r := range repoList { if strings.Contains(r, "/") && r[0:strings.LastIndex(r, "/")] == projectName { - resp += 1 + resp++ } } return resp From d30fc97b3f217b842a3d52f5b15c3f9c440329c8 Mon Sep 17 00:00:00 2001 From: wemeya Date: Fri, 13 May 2016 16:39:22 +0800 Subject: [PATCH 09/29] modify code when project list length is 0 --- api/statistic.go | 6 +++++- dao/project.go | 5 ++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/api/statistic.go b/api/statistic.go index d594d2e2c..ddcbcfd92 100644 --- a/api/statistic.go +++ b/api/statistic.go @@ -57,12 +57,16 @@ func (s *StatisticAPI) Get() { log.Errorf("Error occured in QueryProject, error: %v", err) s.CustomAbort(http.StatusInternalServerError, "Internal error.") } - proMap := map[string]int{} isAdmin, err := dao.IsAdminRole(s.userID) if err != nil { log.Errorf("Error occured in check admin, error: %v", err) s.CustomAbort(http.StatusInternalServerError, "Internal error.") } + proMap := map[string]int{} + proMap["my_project_count"] = 0 + proMap["my_repo_count"] = 0 + proMap["public_project_count"] = 0 + proMap["public_repo_count"] = 0 if isAdmin { proMap["total_project_count"] = len(projectList) proMap["total_repo_count"] = getTotalRepoCount() diff --git a/dao/project.go b/dao/project.go index 97ef37e14..6091ce65a 100644 --- a/dao/project.go +++ b/dao/project.go @@ -113,9 +113,8 @@ func QueryProject(query models.Project) ([]models.Project, error) { sql += " order by p.name " var r []models.Project - _, err0 := o.Raw(sql, queryParam).QueryRows(&r) - - if err0 != nil { + _, err := o.Raw(sql, queryParam).QueryRows(&r) + if err != nil { return nil, err } if isAdmin { From 2561371e377e28f5c9b8d71ab7d95d20d928bf78 Mon Sep 17 00:00:00 2001 From: wemeya Date: Fri, 13 May 2016 16:46:25 +0800 Subject: [PATCH 10/29] change CI error --- dao/project.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dao/project.go b/dao/project.go index 6091ce65a..476350fc7 100644 --- a/dao/project.go +++ b/dao/project.go @@ -113,7 +113,7 @@ func QueryProject(query models.Project) ([]models.Project, error) { sql += " order by p.name " var r []models.Project - _, err := o.Raw(sql, queryParam).QueryRows(&r) + _, err = o.Raw(sql, queryParam).QueryRows(&r) if err != nil { return nil, err } From 9017fe2b569566b78e25a7c4fd1c21167a321d46 Mon Sep 17 00:00:00 2001 From: wemeya Date: Mon, 16 May 2016 17:31:38 +0800 Subject: [PATCH 11/29] change code for statistics api and project detail api --- api/project.go | 29 ++++++++++++++--- api/search.go | 2 +- api/statistic.go | 35 +++++++++----------- dao/dao_test.go | 33 ------------------- dao/project.go | 84 ++++++++++++++++++++---------------------------- 5 files changed, 75 insertions(+), 108 deletions(-) diff --git a/api/project.go b/api/project.go index e14668e10..e933d5a3f 100644 --- a/api/project.go +++ b/api/project.go @@ -118,15 +118,34 @@ func (p *ProjectAPI) Get() { if len(projectName) > 0 { queryProject.Name = "%" + projectName + "%" } - public, _ := p.GetInt("is_public") - queryProject.Public = public - - projectList, err := dao.QueryProject(queryProject) + isPublic := p.GetString("is_public") + if len(isPublic) > 0 { + public, err := strconv.ParseInt(isPublic, 10, 64) + if err != nil { + log.Errorf("Error parsing public property: %d, error: %v", isPublic, err) + p.CustomAbort(http.StatusBadRequest, "invalid project Id") + } + queryProject.Public = int(public) + } + isAdmin, err := dao.IsAdminRole(p.userID) if err != nil { - log.Errorf("Error occurred in QueryProject, error: %v", err) + log.Errorf("Error occured in check admin, error: %v", err) + p.CustomAbort(http.StatusInternalServerError, "Internal error.") + } + var projectList []models.Project + if isAdmin { + projectList, err = dao.GetAllProjects() + } else { + projectList, err = dao.GetUserRelevantProjects(queryProject) + } + if err != nil { + log.Errorf("Error occured in QueryProject, error: %v", err) p.CustomAbort(http.StatusInternalServerError, "Internal error.") } for i := 0; i < len(projectList); i++ { + if isAdmin { + projectList[i].Role = models.PROJECTADMIN + } if projectList[i].Role == models.PROJECTADMIN { projectList[i].Togglable = true } diff --git a/api/search.go b/api/search.go index d47bb5890..f22b6b7f7 100644 --- a/api/search.go +++ b/api/search.go @@ -61,7 +61,7 @@ func (s *SearchAPI) Get() { s.CustomAbort(http.StatusInternalServerError, "internal error") } } else { - projects, err = dao.GetUserRelevantProjects(userID) + projects, err = dao.SearchProjects(userID) if err != nil { log.Errorf("failed to get user %d 's relevant projects: %v", userID, err) s.CustomAbort(http.StatusInternalServerError, "internal error") diff --git a/api/statistic.go b/api/statistic.go index ddcbcfd92..4d0561840 100644 --- a/api/statistic.go +++ b/api/statistic.go @@ -28,40 +28,32 @@ import ( // StatisticAPI handles request to /api/statistics/ type StatisticAPI struct { BaseAPI - userID int - username string + userID int } //Prepare validates the URL and the user func (s *StatisticAPI) Prepare() { - userID, ok := s.GetSession("userId").(int) - if !ok { - s.userID = dao.NonExistUserID - } else { - s.userID = userID - } - username, ok := s.GetSession("username").(string) - if !ok { - log.Warning("failed to get username from session") - s.username = "" - } else { - s.username = username - } + s.userID = s.ValidateUser() } // Get total projects and repos of the user func (s *StatisticAPI) Get() { queryProject := models.Project{UserID: s.userID} - projectList, err := dao.QueryProject(queryProject) - if err != nil { - log.Errorf("Error occured in QueryProject, error: %v", err) - s.CustomAbort(http.StatusInternalServerError, "Internal error.") - } isAdmin, err := dao.IsAdminRole(s.userID) if err != nil { log.Errorf("Error occured in check admin, error: %v", err) s.CustomAbort(http.StatusInternalServerError, "Internal error.") } + var projectList []models.Project + if isAdmin { + projectList, err = dao.GetAllProjects() + } else { + projectList, err = dao.GetUserRelevantProjects(queryProject) + } + if err != nil { + log.Errorf("Error occured in QueryProject, error: %v", err) + s.CustomAbort(http.StatusInternalServerError, "Internal error.") + } proMap := map[string]int{} proMap["my_project_count"] = 0 proMap["my_repo_count"] = 0 @@ -72,6 +64,9 @@ func (s *StatisticAPI) Get() { proMap["total_repo_count"] = getTotalRepoCount() } for i := 0; i < len(projectList); i++ { + if isAdmin { + projectList[i].Role = models.PROJECTADMIN + } if projectList[i].Role == models.PROJECTADMIN || projectList[i].Role == models.DEVELOPER || projectList[i].Role == models.GUEST { proMap["my_project_count"]++ diff --git a/dao/dao_test.go b/dao/dao_test.go index 0ef18faec..b4a48a066 100644 --- a/dao/dao_test.go +++ b/dao/dao_test.go @@ -572,39 +572,6 @@ func TestIsProjectPublic(t *testing.T) { } } -func TestQueryProject(t *testing.T) { - query1 := models.Project{ - UserID: 1, - } - projects, err := QueryProject(query1) - if err != nil { - t.Errorf("Error in Query Project: %v, query: %+v", err, query1) - } - if len(projects) != 2 { - t.Errorf("Expecting get 2 projects, but actual: %d, the list: %+v", len(projects), projects) - } - query2 := models.Project{ - Public: 1, - } - projects, err = QueryProject(query2) - if err != nil { - t.Errorf("Error in Query Project: %v, query: %+v", err, query2) - } - if len(projects) != 1 { - t.Errorf("Expecting get 1 project, but actual: %d, the list: %+v", len(projects), projects) - } - query3 := models.Project{ - UserID: 9, - } - projects, err = QueryProject(query3) - if err != nil { - t.Errorf("Error in Query Project: %v, query: %+v", err, query3) - } - if len(projects) != 0 { - t.Errorf("Expecting get 0 project, but actual: %d, the list: %+v", len(projects), projects) - } -} - func TestGetUserProjectRoles(t *testing.T) { r, err := GetUserProjectRoles(currentUser.UserID, currentProject.ProjectID) if err != nil { diff --git a/dao/project.go b/dao/project.go index 476350fc7..6efc86d43 100644 --- a/dao/project.go +++ b/dao/project.go @@ -79,52 +79,6 @@ func IsProjectPublic(projectName string) bool { return project.Public == 1 } -// QueryProject querys the projects based on publicity and user, disregarding the names etc. -func QueryProject(query models.Project) ([]models.Project, error) { - o := orm.NewOrm() - - sql := `select distinct - p.project_id, p.owner_id, p.name,p.creation_time, p.update_time, p.public` - queryParam := make([]interface{}, 1) - isAdmin, err := IsAdminRole(query.UserID) - if err != nil { - return nil, err - } - - if query.Public == 1 { - //if the project is public - sql += ` from project p where p.deleted = 0 and p.public = ?` - queryParam = append(queryParam, query.Public) - } else if !isAdmin { - //if the user is not admin, should join the project_member table to query his/her projects and role id - sql += `, pm.role role from project p - left join project_member pm on p.project_id = pm.project_id - where p.deleted = 0 and (pm.user_id = ?) ` - queryParam = append(queryParam, query.UserID) - } else if isAdmin { - //if the user is admin, return all projects - sql += ` from project p where p.deleted = 0 ` - } - if query.Name != "" { - sql += " and p.name like ? " - queryParam = append(queryParam, query.Name) - } - - sql += " order by p.name " - - var r []models.Project - _, err = o.Raw(sql, queryParam).QueryRows(&r) - if err != nil { - return nil, err - } - if isAdmin { - for i := 0; i < len(r); i++ { - r[i].Role = models.PROJECTADMIN - } - } - return r, nil -} - //ProjectExists returns whether the project exists according to its name of ID. func ProjectExists(nameOrID interface{}) (bool, error) { o := orm.NewOrm() @@ -218,16 +172,16 @@ func ToggleProjectPublicity(projectID int64, publicity int) error { return err } -// GetUserRelevantProjects returns a project list, +// SearchProjects returns a project list, // which satisfies the following conditions: // 1. the project is not deleted // 2. the prject is public or the user is a member of the project -func GetUserRelevantProjects(userID int) ([]models.Project, error) { +func SearchProjects(userID int) ([]models.Project, error) { o := orm.NewOrm() sql := `select distinct p.project_id, p.name, p.public from project p left join project_member pm on p.project_id = pm.project_id - where (pm.user_id = ? or p.public = 1) and p.deleted = 0` + where (pm.user_id = ? or p.pulic=1) and p.deleted = 0` var projects []models.Project @@ -238,6 +192,38 @@ func GetUserRelevantProjects(userID int) ([]models.Project, error) { return projects, nil } +// GetUserRelevantProjects returns the projects based on publicity and user, disregarding the names etc. +func GetUserRelevantProjects(query models.Project) ([]models.Project, error) { + o := orm.NewOrm() + + sql := `select distinct + p.project_id, p.owner_id, p.name,p.creation_time, p.update_time, p.public, pm.role role + from project p + left join project_member pm on p.project_id = pm.project_id + where p.deleted = 0 and pm.user_id= ?` + + queryParam := make([]interface{}, 1) + queryParam = append(queryParam, query.UserID) + if query.Public == 1 { + sql += ` and p.public = ?` + queryParam = append(queryParam, query.Public) + } + if query.Name != "" { + sql += " and p.name like ? " + queryParam = append(queryParam, query.Name) + } + + sql += " order by p.name " + + var r []models.Project + _, err := o.Raw(sql, queryParam).QueryRows(&r) + + if err != nil { + return nil, err + } + return r, nil +} + // GetAllProjects returns all projects which are not deleted func GetAllProjects() ([]models.Project, error) { o := orm.NewOrm() From ec59807963efaf8633eaa2ac2e270833d1302e71 Mon Sep 17 00:00:00 2001 From: wemeya Date: Mon, 16 May 2016 17:42:36 +0800 Subject: [PATCH 12/29] change dao_test file --- dao/dao_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dao/dao_test.go b/dao/dao_test.go index b4a48a066..65bf710a2 100644 --- a/dao/dao_test.go +++ b/dao/dao_test.go @@ -353,7 +353,8 @@ func TestChangeUserPasswordWithIncorrectOldPassword(t *testing.T) { } func TestQueryRelevantProjectsWhenNoProjectAdded(t *testing.T) { - projects, err := GetUserRelevantProjects(currentUser.UserID) + project := models.Project{UserID: currentUser.UserID} + projects, err := GetUserRelevantProjects(project) if err != nil { t.Errorf("Error occurred in QueryRelevantProjects: %v", err) } @@ -599,7 +600,8 @@ func TestProjectPermission(t *testing.T) { } func TestGetUserRelevantProjects(t *testing.T) { - projects, err := GetUserRelevantProjects(currentUser.UserID) + project := models.Project{UserID: currentUser.UserID} + projects, err := GetUserRelevantProjects(project) if err != nil { t.Errorf("Error occurred in GetUserRelevantProjects: %v", err) } From cf08ed8437c43781d719af9786c84e7cceaeec63 Mon Sep 17 00:00:00 2001 From: wemeya Date: Mon, 16 May 2016 17:50:27 +0800 Subject: [PATCH 13/29] change dao_test file --- dao/dao_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dao/dao_test.go b/dao/dao_test.go index 65bf710a2..dff8fa58c 100644 --- a/dao/dao_test.go +++ b/dao/dao_test.go @@ -353,8 +353,7 @@ func TestChangeUserPasswordWithIncorrectOldPassword(t *testing.T) { } func TestQueryRelevantProjectsWhenNoProjectAdded(t *testing.T) { - project := models.Project{UserID: currentUser.UserID} - projects, err := GetUserRelevantProjects(project) + projects, err := SearchProjects(currentUser.UserID) if err != nil { t.Errorf("Error occurred in QueryRelevantProjects: %v", err) } From 36e6f5f732b0b8856d44d35aa5261b47ce2c1b65 Mon Sep 17 00:00:00 2001 From: wemeya Date: Mon, 16 May 2016 17:57:54 +0800 Subject: [PATCH 14/29] change dao/porject.go file --- dao/project.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dao/project.go b/dao/project.go index 6efc86d43..67e2e1399 100644 --- a/dao/project.go +++ b/dao/project.go @@ -181,7 +181,7 @@ func SearchProjects(userID int) ([]models.Project, error) { sql := `select distinct p.project_id, p.name, p.public from project p left join project_member pm on p.project_id = pm.project_id - where (pm.user_id = ? or p.pulic=1) and p.deleted = 0` + where (pm.user_id = ? or p.pulic = 1) and p.deleted = 0` var projects []models.Project From 9d1a9c31c218c474cc12a79f47620647f2758550 Mon Sep 17 00:00:00 2001 From: wemeya Date: Mon, 16 May 2016 18:02:39 +0800 Subject: [PATCH 15/29] change dao/porject.go file --- dao/project.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dao/project.go b/dao/project.go index 67e2e1399..57df692c9 100644 --- a/dao/project.go +++ b/dao/project.go @@ -181,7 +181,7 @@ func SearchProjects(userID int) ([]models.Project, error) { sql := `select distinct p.project_id, p.name, p.public from project p left join project_member pm on p.project_id = pm.project_id - where (pm.user_id = ? or p.pulic = 1) and p.deleted = 0` + where (pm.user_id = ? or p.public = 1) and p.deleted = 0` var projects []models.Project From facfb03d155c968562ae6e17653efd408e6e5794 Mon Sep 17 00:00:00 2001 From: wemeya Date: Mon, 16 May 2016 18:08:50 +0800 Subject: [PATCH 16/29] change dao_test file --- dao/dao_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dao/dao_test.go b/dao/dao_test.go index dff8fa58c..3845524b9 100644 --- a/dao/dao_test.go +++ b/dao/dao_test.go @@ -604,10 +604,10 @@ func TestGetUserRelevantProjects(t *testing.T) { if err != nil { t.Errorf("Error occurred in GetUserRelevantProjects: %v", err) } - if len(projects) != 2 { - t.Errorf("Expected length of relevant projects is 2, but actual: %d, the projects: %+v", len(projects), projects) + if len(projects) != 1 { + t.Errorf("Expected length of relevant projects is 1, but actual: %d, the projects: %+v", len(projects), projects) } - if projects[1].Name != projectName { + if projects[0].Name != projectName { t.Errorf("Expected project name in the list: %s, actual: %s", projectName, projects[1].Name) } } From 313887967eeceacf1882c6ce4fef9b53b023ee9c Mon Sep 17 00:00:00 2001 From: wemeya Date: Tue, 17 May 2016 17:03:40 +0800 Subject: [PATCH 17/29] change api for statistics and project --- api/project.go | 51 +++++++++++++++++++++++++++--------------------- api/search.go | 2 +- api/statistic.go | 5 ++--- dao/dao_test.go | 5 ++--- dao/project.go | 37 +++++++++++++++++++++++++---------- 5 files changed, 61 insertions(+), 39 deletions(-) diff --git a/api/project.go b/api/project.go index e933d5a3f..989f5a5ab 100644 --- a/api/project.go +++ b/api/project.go @@ -113,34 +113,41 @@ func (p *ProjectAPI) Head() { // Get ... func (p *ProjectAPI) Get() { - queryProject := models.Project{UserID: p.userID} - projectName := p.GetString("project_name") - if len(projectName) > 0 { - queryProject.Name = "%" + projectName + "%" - } - isPublic := p.GetString("is_public") - if len(isPublic) > 0 { - public, err := strconv.ParseInt(isPublic, 10, 64) - if err != nil { - log.Errorf("Error parsing public property: %d, error: %v", isPublic, err) - p.CustomAbort(http.StatusBadRequest, "invalid project Id") - } - queryProject.Public = int(public) - } + var projectList []models.Project isAdmin, err := dao.IsAdminRole(p.userID) if err != nil { log.Errorf("Error occured in check admin, error: %v", err) p.CustomAbort(http.StatusInternalServerError, "Internal error.") } - var projectList []models.Project - if isAdmin { - projectList, err = dao.GetAllProjects() - } else { - projectList, err = dao.GetUserRelevantProjects(queryProject) + projectName := p.GetString("project_name") + if len(projectName) > 0 { + projectName = "%" + projectName + "%" } - if err != nil { - log.Errorf("Error occured in QueryProject, error: %v", err) - p.CustomAbort(http.StatusInternalServerError, "Internal error.") + var public int + isPublic := p.GetString("is_public") + if len(isPublic) > 0 { + public, err = strconv.Atoi(isPublic) + if err != nil { + log.Errorf("Error parsing public property: %d, error: %v", isPublic, err) + p.CustomAbort(http.StatusBadRequest, "invalid project Id") + } + } + if public == 1 { + projectList, err = dao.GetPublicProjects(projectName) + if err != nil { + log.Errorf("Error occured in GetPulicProjects, error: %v", err) + p.CustomAbort(http.StatusInternalServerError, "Internal error.") + } + } else { + if isAdmin { + projectList, err = dao.GetAllProjects(projectName) + } else { + projectList, err = dao.GetUserRelevantProjects(p.userID, projectName) + } + if err != nil { + log.Errorf("Error occured in GetUserRelevantProjects, error: %v", err) + p.CustomAbort(http.StatusInternalServerError, "Internal error.") + } } for i := 0; i < len(projectList); i++ { if isAdmin { diff --git a/api/search.go b/api/search.go index f22b6b7f7..3acdc7ca8 100644 --- a/api/search.go +++ b/api/search.go @@ -55,7 +55,7 @@ func (s *SearchAPI) Get() { var projects []models.Project if isSysAdmin { - projects, err = dao.GetAllProjects() + projects, err = dao.GetAllProjects("") if err != nil { log.Errorf("failed to get all projects: %v", err) s.CustomAbort(http.StatusInternalServerError, "internal error") diff --git a/api/statistic.go b/api/statistic.go index 4d0561840..e90140b17 100644 --- a/api/statistic.go +++ b/api/statistic.go @@ -38,7 +38,6 @@ func (s *StatisticAPI) Prepare() { // Get total projects and repos of the user func (s *StatisticAPI) Get() { - queryProject := models.Project{UserID: s.userID} isAdmin, err := dao.IsAdminRole(s.userID) if err != nil { log.Errorf("Error occured in check admin, error: %v", err) @@ -46,9 +45,9 @@ func (s *StatisticAPI) Get() { } var projectList []models.Project if isAdmin { - projectList, err = dao.GetAllProjects() + projectList, err = dao.GetAllProjects("") } else { - projectList, err = dao.GetUserRelevantProjects(queryProject) + projectList, err = dao.GetUserRelevantProjects(s.userID, "") } if err != nil { log.Errorf("Error occured in QueryProject, error: %v", err) diff --git a/dao/dao_test.go b/dao/dao_test.go index 3845524b9..7f9f07978 100644 --- a/dao/dao_test.go +++ b/dao/dao_test.go @@ -599,8 +599,7 @@ func TestProjectPermission(t *testing.T) { } func TestGetUserRelevantProjects(t *testing.T) { - project := models.Project{UserID: currentUser.UserID} - projects, err := GetUserRelevantProjects(project) + projects, err := GetUserRelevantProjects(currentUser.UserID, "") if err != nil { t.Errorf("Error occurred in GetUserRelevantProjects: %v", err) } @@ -613,7 +612,7 @@ func TestGetUserRelevantProjects(t *testing.T) { } func TestGetAllProjects(t *testing.T) { - projects, err := GetAllProjects() + projects, err := GetAllProjects("") if err != nil { t.Errorf("Error occurred in GetAllProjects: %v", err) } diff --git a/dao/project.go b/dao/project.go index 57df692c9..616a50716 100644 --- a/dao/project.go +++ b/dao/project.go @@ -193,7 +193,7 @@ func SearchProjects(userID int) ([]models.Project, error) { } // GetUserRelevantProjects returns the projects based on publicity and user, disregarding the names etc. -func GetUserRelevantProjects(query models.Project) ([]models.Project, error) { +func GetUserRelevantProjects(userId int, projectName string) ([]models.Project, error) { o := orm.NewOrm() sql := `select distinct @@ -203,33 +203,50 @@ func GetUserRelevantProjects(query models.Project) ([]models.Project, error) { where p.deleted = 0 and pm.user_id= ?` queryParam := make([]interface{}, 1) - queryParam = append(queryParam, query.UserID) - if query.Public == 1 { - sql += ` and p.public = ?` - queryParam = append(queryParam, query.Public) - } - if query.Name != "" { + queryParam = append(queryParam, userId) + if projectName != "" { sql += " and p.name like ? " - queryParam = append(queryParam, query.Name) + queryParam = append(queryParam, projectName) } sql += " order by p.name " var r []models.Project _, err := o.Raw(sql, queryParam).QueryRows(&r) - if err != nil { return nil, err } return r, nil } +//GetPublicProjects return all public projects whose name like projectName +func GetPublicProjects(projectName string) ([]models.Project, error) { + o := orm.NewOrm() + var publicProjects []models.Project + sql := `select project_id, name, public + from project + where deleted = 0 and public=1` + if len(projectName) > 0 { + sql += " and name like '" + projectName + "'" + } + sql += " order by name " + _, err := o.Raw(sql).QueryRows(&publicProjects) + if err != nil { + return nil, err + } + return publicProjects, nil +} + // GetAllProjects returns all projects which are not deleted -func GetAllProjects() ([]models.Project, error) { +func GetAllProjects(projectName string) ([]models.Project, error) { o := orm.NewOrm() sql := `select project_id, name, public from project where deleted = 0` + if len(projectName) > 0 { + sql += " and name like '" + projectName + "'" + } + sql += " order by name " var projects []models.Project if _, err := o.Raw(sql).QueryRows(&projects); err != nil { return nil, err From af200d6e4cc35f6dc128363042e2d5797e800332 Mon Sep 17 00:00:00 2001 From: wemeya Date: Tue, 17 May 2016 17:10:31 +0800 Subject: [PATCH 18/29] change func parameter according to travis CI --- dao/project.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dao/project.go b/dao/project.go index 616a50716..81de39701 100644 --- a/dao/project.go +++ b/dao/project.go @@ -193,7 +193,7 @@ func SearchProjects(userID int) ([]models.Project, error) { } // GetUserRelevantProjects returns the projects based on publicity and user, disregarding the names etc. -func GetUserRelevantProjects(userId int, projectName string) ([]models.Project, error) { +func GetUserRelevantProjects(userID int, projectName string) ([]models.Project, error) { o := orm.NewOrm() sql := `select distinct @@ -203,7 +203,7 @@ func GetUserRelevantProjects(userId int, projectName string) ([]models.Project, where p.deleted = 0 and pm.user_id= ?` queryParam := make([]interface{}, 1) - queryParam = append(queryParam, userId) + queryParam = append(queryParam, userID) if projectName != "" { sql += " and p.name like ? " queryParam = append(queryParam, projectName) From 89fce7ed222e34832004e26eff48589200ff885f Mon Sep 17 00:00:00 2001 From: wemeya Date: Wed, 18 May 2016 10:30:55 +0800 Subject: [PATCH 19/29] change comment and add sql fields --- dao/project.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dao/project.go b/dao/project.go index 81de39701..c7d487c7c 100644 --- a/dao/project.go +++ b/dao/project.go @@ -192,7 +192,7 @@ func SearchProjects(userID int) ([]models.Project, error) { return projects, nil } -// GetUserRelevantProjects returns the projects based on publicity and user, disregarding the names etc. +// GetUserRelevantProjects returns the projects of the user which are not deleted and name like projectName func GetUserRelevantProjects(userID int, projectName string) ([]models.Project, error) { o := orm.NewOrm() @@ -219,11 +219,11 @@ func GetUserRelevantProjects(userID int, projectName string) ([]models.Project, return r, nil } -//GetPublicProjects return all public projects whose name like projectName +//GetPublicProjects returns all public projects whose name like projectName func GetPublicProjects(projectName string) ([]models.Project, error) { o := orm.NewOrm() var publicProjects []models.Project - sql := `select project_id, name, public + sql := `select project_id, owner_id, creation_time, update_time, name, public from project where deleted = 0 and public=1` if len(projectName) > 0 { @@ -237,10 +237,10 @@ func GetPublicProjects(projectName string) ([]models.Project, error) { return publicProjects, nil } -// GetAllProjects returns all projects which are not deleted +// GetAllProjects returns all projects which are not deleted and name like projectName func GetAllProjects(projectName string) ([]models.Project, error) { o := orm.NewOrm() - sql := `select project_id, name, public + sql := `select project_id, owner_id, creation_time, update_time, name, public from project where deleted = 0` if len(projectName) > 0 { From 3e1bf8c862cb5ce0a157a58416f0b2dc48f4ce68 Mon Sep 17 00:00:00 2001 From: wemeya Date: Wed, 18 May 2016 14:36:20 +0800 Subject: [PATCH 20/29] change code for statistics and project api --- api/project.go | 32 ++++++++++++++++---------------- api/statistic.go | 14 ++++++++++---- dao/project.go | 15 ++++++++------- 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/api/project.go b/api/project.go index 989f5a5ab..2cd7772df 100644 --- a/api/project.go +++ b/api/project.go @@ -114,16 +114,12 @@ func (p *ProjectAPI) Head() { // Get ... func (p *ProjectAPI) Get() { var projectList []models.Project - isAdmin, err := dao.IsAdminRole(p.userID) - if err != nil { - log.Errorf("Error occured in check admin, error: %v", err) - p.CustomAbort(http.StatusInternalServerError, "Internal error.") - } projectName := p.GetString("project_name") if len(projectName) > 0 { projectName = "%" + projectName + "%" } var public int + var err error isPublic := p.GetString("is_public") if len(isPublic) > 0 { public, err = strconv.Atoi(isPublic) @@ -132,29 +128,33 @@ func (p *ProjectAPI) Get() { p.CustomAbort(http.StatusBadRequest, "invalid project Id") } } + isAdmin := false if public == 1 { projectList, err = dao.GetPublicProjects(projectName) + } else { + isAdmin, err = dao.IsAdminRole(p.userID) if err != nil { - log.Errorf("Error occured in GetPulicProjects, error: %v", err) + log.Errorf("Error occured in check admin, error: %v", err) p.CustomAbort(http.StatusInternalServerError, "Internal error.") } - } else { if isAdmin { projectList, err = dao.GetAllProjects(projectName) } else { projectList, err = dao.GetUserRelevantProjects(p.userID, projectName) } - if err != nil { - log.Errorf("Error occured in GetUserRelevantProjects, error: %v", err) - p.CustomAbort(http.StatusInternalServerError, "Internal error.") - } + } + if err != nil { + log.Errorf("Error occured in GetUserRelevantProjects, error: %v", err) + p.CustomAbort(http.StatusInternalServerError, "Internal error.") } for i := 0; i < len(projectList); i++ { - if isAdmin { - projectList[i].Role = models.PROJECTADMIN - } - if projectList[i].Role == models.PROJECTADMIN { - projectList[i].Togglable = true + if public != 1 { + if isAdmin { + projectList[i].Role = models.PROJECTADMIN + } + if projectList[i].Role == models.PROJECTADMIN { + projectList[i].Togglable = true + } } projectList[i].RepoCount = getRepoCountByProject(projectList[i].Name) } diff --git a/api/statistic.go b/api/statistic.go index e90140b17..67a7cc388 100644 --- a/api/statistic.go +++ b/api/statistic.go @@ -58,6 +58,16 @@ func (s *StatisticAPI) Get() { proMap["my_repo_count"] = 0 proMap["public_project_count"] = 0 proMap["public_repo_count"] = 0 + var publicProjects []models.Project + publicProjects, err = dao.GetPublicProjects("") + if err != nil { + log.Errorf("Error occured in QueryPublicProject, error: %v", err) + s.CustomAbort(http.StatusInternalServerError, "Internal error.") + } + proMap["public_project_count"] = len(publicProjects) + for i := 0; i < len(publicProjects); i++ { + proMap["public_repo_count"] += getRepoCountByProject(publicProjects[i].Name) + } if isAdmin { proMap["total_project_count"] = len(projectList) proMap["total_repo_count"] = getTotalRepoCount() @@ -71,10 +81,6 @@ func (s *StatisticAPI) Get() { proMap["my_project_count"]++ proMap["my_repo_count"] += getRepoCountByProject(projectList[i].Name) } - if projectList[i].Public == 1 { - proMap["public_project_count"]++ - proMap["public_repo_count"] += getRepoCountByProject(projectList[i].Name) - } } s.Data["json"] = proMap s.ServeJSON() diff --git a/dao/project.go b/dao/project.go index c7d487c7c..c4dde5cdb 100644 --- a/dao/project.go +++ b/dao/project.go @@ -195,7 +195,6 @@ func SearchProjects(userID int) ([]models.Project, error) { // GetUserRelevantProjects returns the projects of the user which are not deleted and name like projectName func GetUserRelevantProjects(userID int, projectName string) ([]models.Project, error) { o := orm.NewOrm() - sql := `select distinct p.project_id, p.owner_id, p.name,p.creation_time, p.update_time, p.public, pm.role role from project p @@ -208,9 +207,7 @@ func GetUserRelevantProjects(userID int, projectName string) ([]models.Project, sql += " and p.name like ? " queryParam = append(queryParam, projectName) } - sql += " order by p.name " - var r []models.Project _, err := o.Raw(sql, queryParam).QueryRows(&r) if err != nil { @@ -226,11 +223,13 @@ func GetPublicProjects(projectName string) ([]models.Project, error) { sql := `select project_id, owner_id, creation_time, update_time, name, public from project where deleted = 0 and public=1` + queryParam := make([]interface{}, 1) if len(projectName) > 0 { - sql += " and name like '" + projectName + "'" + sql += " and name like ? " + queryParam = append(queryParam, projectName) } sql += " order by name " - _, err := o.Raw(sql).QueryRows(&publicProjects) + _, err := o.Raw(sql, queryParam).QueryRows(&publicProjects) if err != nil { return nil, err } @@ -243,12 +242,14 @@ func GetAllProjects(projectName string) ([]models.Project, error) { sql := `select project_id, owner_id, creation_time, update_time, name, public from project where deleted = 0` + queryParam := make([]interface{}, 1) if len(projectName) > 0 { - sql += " and name like '" + projectName + "'" + sql += " and name like ? " + queryParam = append(queryParam, projectName) } sql += " order by name " var projects []models.Project - if _, err := o.Raw(sql).QueryRows(&projects); err != nil { + if _, err := o.Raw(sql, queryParam).QueryRows(&projects); err != nil { return nil, err } return projects, nil From 155f8dc1a87c4c86a2af694090203ebb44f61107 Mon Sep 17 00:00:00 2001 From: wemeya Date: Wed, 18 May 2016 15:07:54 +0800 Subject: [PATCH 21/29] modify error message --- api/project.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/project.go b/api/project.go index 2cd7772df..90ccbdb8c 100644 --- a/api/project.go +++ b/api/project.go @@ -144,7 +144,7 @@ func (p *ProjectAPI) Get() { } } if err != nil { - log.Errorf("Error occured in GetUserRelevantProjects, error: %v", err) + log.Errorf("Error occured in get projects info, error: %v", err) p.CustomAbort(http.StatusInternalServerError, "Internal error.") } for i := 0; i < len(projectList); i++ { From 1f44e2aa8be78904a9727db59ccb0c4fdc0e0187 Mon Sep 17 00:00:00 2001 From: wemeya Date: Wed, 18 May 2016 17:48:05 +0800 Subject: [PATCH 22/29] add a new func to reuse code --- dao/project.go | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/dao/project.go b/dao/project.go index c4dde5cdb..8ff03fb28 100644 --- a/dao/project.go +++ b/dao/project.go @@ -218,31 +218,33 @@ func GetUserRelevantProjects(userID int, projectName string) ([]models.Project, //GetPublicProjects returns all public projects whose name like projectName func GetPublicProjects(projectName string) ([]models.Project, error) { - o := orm.NewOrm() - var publicProjects []models.Project - sql := `select project_id, owner_id, creation_time, update_time, name, public - from project - where deleted = 0 and public=1` - queryParam := make([]interface{}, 1) - if len(projectName) > 0 { - sql += " and name like ? " - queryParam = append(queryParam, projectName) - } - sql += " order by name " - _, err := o.Raw(sql, queryParam).QueryRows(&publicProjects) + publicProjects, err := getProjects(1, projectName) if err != nil { return nil, err + } return publicProjects, nil } // GetAllProjects returns all projects which are not deleted and name like projectName func GetAllProjects(projectName string) ([]models.Project, error) { + allProjects, err := getProjects(0, projectName) + if err != nil { + return nil, err + } + return allProjects, nil +} + +func getProjects(public int, projectName string) ([]models.Project, error) { o := orm.NewOrm() sql := `select project_id, owner_id, creation_time, update_time, name, public from project where deleted = 0` queryParam := make([]interface{}, 1) + if public == 1 { + sql += "and public = ?" + queryParam = append(queryParam, public) + } if len(projectName) > 0 { sql += " and name like ? " queryParam = append(queryParam, projectName) From 24c47914d7fff7628cabf7f676294f5dab7a9237 Mon Sep 17 00:00:00 2001 From: kunw Date: Thu, 19 May 2016 12:50:32 +0800 Subject: [PATCH 23/29] added search feature of UI and other updates for interactions. --- controllers/ng/search.go | 9 ++++ static/ng/resources/css/search.css | 9 ++++ .../repository/list-repository.directive.js | 17 ++++-- .../search/search-input.directive.html | 5 ++ .../search/search-input.directive.js | 54 +++++++++++++++++++ static/ng/resources/js/harbor.config.js | 15 +++++- static/ng/resources/js/harbor.module.js | 1 + .../js/layout/header/header.controller.js | 10 ++-- .../navigation-header.directive.html | 2 +- .../navigation/navigation-header.directive.js | 4 ++ .../reset-password.controller.js | 13 +---- .../js/layout/search/search.controller.js | 31 +++++++++++ .../js/layout/search/search.module.js | 9 ++++ .../js/services/search/services.search.js | 22 +++----- .../js/session/session.current-user.js | 2 +- ui/ngrouter.go | 2 +- views/ng/dashboard.htm | 2 +- views/ng/search.htm | 24 +++++++++ views/ng/sections/header-content.htm | 6 +-- views/ng/sections/header-include.htm | 5 ++ 20 files changed, 201 insertions(+), 41 deletions(-) create mode 100644 controllers/ng/search.go create mode 100644 static/ng/resources/css/search.css create mode 100644 static/ng/resources/js/components/search/search-input.directive.html create mode 100644 static/ng/resources/js/components/search/search-input.directive.js create mode 100644 static/ng/resources/js/layout/search/search.controller.js create mode 100644 static/ng/resources/js/layout/search/search.module.js create mode 100644 views/ng/search.htm diff --git a/controllers/ng/search.go b/controllers/ng/search.go new file mode 100644 index 000000000..341c864a0 --- /dev/null +++ b/controllers/ng/search.go @@ -0,0 +1,9 @@ +package ng + +type SearchController struct { + BaseController +} + +func (sc *SearchController) Get() { + sc.Forward("Search", "search.htm") +} diff --git a/static/ng/resources/css/search.css b/static/ng/resources/css/search.css new file mode 100644 index 000000000..d2b2b9f27 --- /dev/null +++ b/static/ng/resources/css/search.css @@ -0,0 +1,9 @@ +.search-result { + min-height: 200px; + max-height: 200px; + overflow-y: auto; +} + +.search-result li { + margin-bottom: 15px; +} \ No newline at end of file diff --git a/static/ng/resources/js/components/repository/list-repository.directive.js b/static/ng/resources/js/components/repository/list-repository.directive.js index a2d4eb3f6..cc010bf70 100644 --- a/static/ng/resources/js/components/repository/list-repository.directive.js +++ b/static/ng/resources/js/components/repository/list-repository.directive.js @@ -5,12 +5,23 @@ .module('harbor.repository') .directive('listRepository', listRepository); - ListRepositoryController.$inject = ['$scope', 'ListRepositoryService', 'DeleteRepositoryService', '$routeParams', '$filter', 'trFilter']; + ListRepositoryController.$inject = ['$scope', 'ListRepositoryService', 'DeleteRepositoryService', '$routeParams', '$filter', 'trFilter', '$location']; - function ListRepositoryController($scope, ListRepositoryService, DeleteRepositoryService, $routeParams, $filter, trFilter) { + function ListRepositoryController($scope, ListRepositoryService, DeleteRepositoryService, $routeParams, $filter, trFilter, $location) { var vm = this; + + vm.filterInput = ''; + + var hashValue = $location.hash(); + if(hashValue) { + var slashIndex = hashValue.indexOf('/'); + if(slashIndex >=0) { + vm.filterInput = hashValue.substring(slashIndex + 1); + }else{ + vm.filterInput = hashValue; + } + } - vm.filterInput = ""; vm.retrieve = retrieve; vm.projectId = $routeParams.project_id; vm.tagCount = {}; diff --git a/static/ng/resources/js/components/search/search-input.directive.html b/static/ng/resources/js/components/search/search-input.directive.html new file mode 100644 index 000000000..c60629955 --- /dev/null +++ b/static/ng/resources/js/components/search/search-input.directive.html @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/static/ng/resources/js/components/search/search-input.directive.js b/static/ng/resources/js/components/search/search-input.directive.js new file mode 100644 index 000000000..fe9eaaac2 --- /dev/null +++ b/static/ng/resources/js/components/search/search-input.directive.js @@ -0,0 +1,54 @@ +(function() { + + 'use strict'; + + angular + .module('harbor.search') + .directive('searchInput', searchInput); + + SearchInputController.$inject = ['$scope', '$location', '$window']; + + function SearchInputController($scope, $location, $window) { + var vm = this; + + vm.searchFor = searchFor; + + function searchFor(searchContent) { + $location + .path('/ng/search') + .search({'q': searchContent}); + $window.location.href = $location.url(); + } + + } + + function searchInput() { + + var directive = { + 'restrict': 'E', + 'templateUrl': '/static/ng/resources/js/components/search/search-input.directive.html', + 'scope': { + 'searchInput': '=', + }, + 'link': link, + 'controller': SearchInputController, + 'controllerAs': 'vm', + 'bindToController': true + }; + return directive; + + function link(scope, element, attrs, ctrl) { + element + .find('input[type="text"]') + .on('keydown', keydownHandler); + + function keydownHandler(e) { + if(e.keyCode === 13) { + ctrl.searchFor($(this).val()); + } + } + + } + } + +})(); \ No newline at end of file diff --git a/static/ng/resources/js/harbor.config.js b/static/ng/resources/js/harbor.config.js index b7f8990de..d256c5cf2 100644 --- a/static/ng/resources/js/harbor.config.js +++ b/static/ng/resources/js/harbor.config.js @@ -9,9 +9,22 @@ .config(function($httpProvider) { $httpProvider.defaults.headers.common = {'Accept': 'application/json, text/javascript, */*; q=0.01'}; }) + .factory('getParameterByName', getParameterByName) .filter('dateL', localizeDate) .filter('tr', tr); - + + function getParameterByName() { + return get; + function get(name, url) { + name = name.replace(/[\[\]]/g, "\\$&"); + var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), + results = regex.exec(url); + if (!results) return null; + if (!results[2]) return ''; + return decodeURIComponent(results[2].replace(/\+/g, " ")); + } + } + function localizeDate() { return filter; diff --git a/static/ng/resources/js/harbor.module.js b/static/ng/resources/js/harbor.module.js index f0f190da6..0a18b1dd2 100644 --- a/static/ng/resources/js/harbor.module.js +++ b/static/ng/resources/js/harbor.module.js @@ -21,6 +21,7 @@ 'harbor.layout.system.management', 'harbor.layout.log', 'harbor.layout.admin.option', + 'harbor.layout.search', 'harbor.services.i18n', 'harbor.services.project', 'harbor.services.user', diff --git a/static/ng/resources/js/layout/header/header.controller.js b/static/ng/resources/js/layout/header/header.controller.js index fa28cddc6..754a9d3d0 100644 --- a/static/ng/resources/js/layout/header/header.controller.js +++ b/static/ng/resources/js/layout/header/header.controller.js @@ -6,10 +6,14 @@ .module('harbor.layout.header') .controller('HeaderController', HeaderController); - HeaderController.$inject = ['$scope', 'I18nService', '$cookies', '$window']; + HeaderController.$inject = ['$scope', '$window', 'getParameterByName']; - function HeaderController($scope, I18nService, $cookies, $window) { - + function HeaderController($scope, $window, getParameterByName) { + var vm = this; + if($window.location.search) { + vm.searchInput = getParameterByName('q', $window.location.search); + console.log('vm.searchInput at header:' + vm.searchInput); + } } })(); \ No newline at end of file diff --git a/static/ng/resources/js/layout/navigation/navigation-header.directive.html b/static/ng/resources/js/layout/navigation/navigation-header.directive.html index 936471a6c..2a28ef684 100644 --- a/static/ng/resources/js/layout/navigation/navigation-header.directive.html +++ b/static/ng/resources/js/layout/navigation/navigation-header.directive.html @@ -1,4 +1,4 @@ -