diff --git a/.travis.yml b/.travis.yml
index f28dc7230..a23fba418 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,3 +1,5 @@
+sudo: true
+
language: go
go:
@@ -5,10 +7,32 @@ go:
go_import_path: github.com/vmware/harbor
-#service:
-# - mysql
+services:
+ - docker
+ - mysql
-env: DB_HOST=127.0.0.1 DB_PORT=3306 DB_USR=root DB_PWD=
+dist: trusty
+addons:
+ apt:
+ packages:
+ - mysql-server-5.6
+ - mysql-client-core-5.6
+ - mysql-client-5.6
+
+env:
+ DB_HOST: 127.0.0.1
+ DB_PORT: 3306
+ DB_USR: root
+ DB_PWD:
+ DOCKER_COMPOSE_VERSION: 1.7.1
+ HARBOR_ADMIN: admin
+ HARBOR_ADMIN_PASSWD: Harbor12345
+
+before_install:
+ - ./tests/hostcfg.sh
+ - cd Deploy
+ - ./prepare
+ - cd ..
install:
- sudo apt-get update && sudo apt-get install -y libldap2-dev
@@ -29,12 +53,29 @@ install:
- go get -d github.com/go-sql-driver/mysql
- go get github.com/golang/lint/golint
- go get github.com/GeertJohan/fgt
-
+ - sudo apt-get install -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" docker-engine=1.11.1-0~trusty
+ - sudo rm /usr/local/bin/docker-compose
+ - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
+ - chmod +x docker-compose
+ - sudo mv docker-compose /usr/local/bin
+ - go get github.com/dghubble/sling
+ - go get github.com/stretchr/testify
+
before_script:
# create tables and load data
- mysql < ./Deploy/db/registry.sql -uroot --verbose
script:
- - go list ./... | grep -v /vendor/ | xargs -L1 fgt golint
- - go list ./... | grep -v 'vendor' | xargs -L1 go vet
- - go list ./... | grep -v 'vendor' | xargs -L1 go test -v
+ - go list ./... | grep -v 'tests' | grep -v /vendor/ | xargs -L1 fgt golint
+ - go list ./... | grep -v 'tests' | grep -v 'vendor' | xargs -L1 go vet
+ - go list ./... | grep -v 'tests' | grep -v 'vendor' | xargs -L1 go test -v
+
+ - docker-compose -f Deploy/docker-compose.yml up -d
+
+ - docker ps
+ - go run tests/startuptest.go http://localhost/
+ - go run tests/userlogintest.go -name ${HARBOR_ADMIN} -passwd ${HARBOR_ADMIN_PASSWD}
+
+
+ # test for API
+ - go test -v ./tests/apitests
diff --git a/api/member.go b/api/member.go
index b86e36f5d..685dc132e 100644
--- a/api/member.go
+++ b/api/member.go
@@ -33,7 +33,7 @@ type ProjectMemberAPI struct {
}
type memberReq struct {
- Username string `json:"user_name"`
+ Username string `json:"username"`
UserID int `json:"user_id"`
Roles []int `json:"roles"`
}
@@ -104,7 +104,7 @@ func (pma *ProjectMemberAPI) Get() {
log.Errorf("Error occurred in GetUser, error: %v", err)
pma.CustomAbort(http.StatusInternalServerError, "Internal error.")
}
- result["user_name"] = user.Username
+ result["username"] = user.Username
result["user_id"] = pma.memberID
result["roles"] = roleList
pma.Data["json"] = result
diff --git a/api/replication_policy.go b/api/replication_policy.go
index d0e9946cb..26b5b0a61 100644
--- a/api/replication_policy.go
+++ b/api/replication_policy.go
@@ -14,8 +14,6 @@ import (
// RepPolicyAPI handles /api/replicationPolicies /api/replicationPolicies/:id/enablement
type RepPolicyAPI struct {
BaseAPI
- policyID int64
- policy *models.RepPolicy
}
// Prepare validates whether the user has system admin role
@@ -214,11 +212,11 @@ func (pa *RepPolicyAPI) UpdateEnablement() {
return
}
- if pa.policy.Enabled == e.Enabled {
+ if policy.Enabled == e.Enabled {
return
}
- if err := dao.UpdateRepPolicyEnablement(pa.policyID, e.Enabled); err != nil {
+ if err := dao.UpdateRepPolicyEnablement(id, e.Enabled); err != nil {
log.Errorf("Failed to update policy enablement in DB, error: %v", err)
pa.RenderError(http.StatusInternalServerError, "Internal Error")
return
@@ -226,18 +224,18 @@ func (pa *RepPolicyAPI) UpdateEnablement() {
if e.Enabled == 1 {
go func() {
- if err := TriggerReplication(pa.policyID, "", nil, models.RepOpTransfer); err != nil {
- log.Errorf("failed to trigger replication of %d: %v", pa.policyID, err)
+ if err := TriggerReplication(id, "", nil, models.RepOpTransfer); err != nil {
+ log.Errorf("failed to trigger replication of %d: %v", id, err)
} else {
- log.Infof("replication of %d triggered", pa.policyID)
+ log.Infof("replication of %d triggered", id)
}
}()
} else {
go func() {
- if err := postReplicationAction(pa.policyID, "stop"); err != nil {
- log.Errorf("failed to stop replication of %d: %v", pa.policyID, err)
+ if err := postReplicationAction(id, "stop"); err != nil {
+ log.Errorf("failed to stop replication of %d: %v", id, err)
} else {
- log.Infof("try to stop replication of %d", pa.policyID)
+ log.Infof("try to stop replication of %d", id)
}
}()
}
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
index e4c274984..4d94f4ce6 100644
--- a/docs/swagger.yaml
+++ b/docs/swagger.yaml
@@ -4,7 +4,7 @@ swagger: '2.0'
info:
title: Harbor API
description: These APIs provide services for manipulating Harbor project.
- version: "0.1.0"
+ version: "0.1.1"
# the domain of the service
host: localhost
# array of all schemes that your API supports
@@ -167,7 +167,7 @@ paths:
- name: access_log
in: body
schema:
- $ref: '#/definitions/AccessLog'
+ $ref: '#/definitions/AccessLogFilter'
description: Search results of access logs.
tags:
- Products
@@ -204,7 +204,7 @@ paths:
schema:
type: array
items:
- $ref: '#/definitions/Role'
+ $ref: '#/definitions/User'
400:
description: Illegal format of provided ID value.
401:
@@ -567,7 +567,7 @@ paths:
schema:
type: array
items:
- $ref: '#/definitions/Repository'
+ type: string
400:
description: Invalid project ID.
403:
@@ -719,12 +719,41 @@ definitions:
description: Search results of the projects that matched the filter keywords.
type: array
items:
- $ref: '#/definitions/Project'
+ $ref: '#/definitions/SearchProject'
repositories:
description: Search results of the repositories that matched the filter keywords.
type: array
items:
- $ref: '#/definitions/Repository'
+ $ref: '#/definitions/SearchRepository'
+ SearchProject:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ description: The ID of project
+ name:
+ type: string
+ description: The name of the project
+ public:
+ type: integer
+ format: int
+ description: The flag to indicate the publicity of the project (1 is public, 0 is non-public)
+ SearchRepository:
+ type: object
+ properties:
+ repository_name:
+ type: string
+ description: The name of the repository
+ project_name:
+ type: string
+ description: The name of the project that the repository belongs to
+ project_id:
+ type: integer
+ description: The ID of the project that the repository belongs to
+ project_public:
+ type: integer
+ description: The flag to indicate the publicity of the project that the repository belongs to (1 is public, 0 is not)
Project:
type: object
properties:
@@ -736,30 +765,39 @@ definitions:
type: integer
format: int32
description: The owner ID of the project always means the creator of the project.
- project_name:
+ name:
type: string
description: The name of the project.
creation_time:
type: string
description: The creation time of the project.
+ update_time:
+ type: string
+ description: The update time of the project.
deleted:
type: integer
format: int32
- description: A deletion mark of the project.
+ description: A deletion mark of the project (1 means it's deleted, 0 is not)
user_id:
type: integer
format: int32
description: A relation field to the user table.
owner_name:
type: string
- description: The owner name of tthe project always means the creator of the project.
+ description: The owner name of the project.
public:
type: boolean
format: boolean
description: The public status of the project.
togglable:
type: boolean
- description: Correspond to the UI about showing the public status of the project.
+ description: Correspond to the UI about whether the project's publicity is updatable (for UI)
+ current_user_role_id:
+ type: integer
+ description: The role ID of the current user who triggered the API (for UI)
+ repo_count:
+ type: integer
+ description: The number of the repositories under this project.
Repository:
type: object
properties:
@@ -794,6 +832,7 @@ definitions:
user_id:
type: integer
format: int32
+ description: The ID of the user.
username:
type: string
email:
@@ -816,7 +855,7 @@ definitions:
new_password:
type: string
description: New password for marking as to be updated.
- AccessLog:
+ AccessLogFilter:
type: object
properties:
username:
@@ -825,14 +864,32 @@ definitions:
keywords:
type: string
description: Operation name specified when project created.
- beginTimestamp:
+ begin_timestamp:
type: integer
- format: int32
+ format: int64
description: Begin timestamp for querying access logs.
- endTimestamp:
+ end_timestamp:
type: integer
- format: int32
+ format: int64
description: End timestamp for querying accessl logs.
+ AccessLog:
+ type: object
+ properties:
+ log_id:
+ type: integer
+ description: The ID of the log entry.
+ repo_name:
+ type: string
+ description: Name of the repository in this log entry.
+ repo_tag:
+ type: string
+ description: Tag of the repository in this log entry.
+ operation:
+ type: string
+ description: The operation against the repository in this log entry.
+ op_time:
+ type: time
+ description: The time when this operation is triggered.
Role:
type: object
properties:
@@ -855,7 +912,7 @@ definitions:
type: integer
format: int32
description: Role ID for updating project role member.
- user_name:
+ username:
type: string
description: Username relevant to a project role member.
TopRepo:
diff --git a/models/accesslog.go b/models/accesslog.go
index b5d919943..336e7bd08 100644
--- a/models/accesslog.go
+++ b/models/accesslog.go
@@ -21,19 +21,18 @@ import (
// AccessLog holds information about logs which are used to record the actions that user take to the resourses.
type AccessLog struct {
- LogID int `orm:"pk;column(log_id)" json:"LogId"`
- UserID int `orm:"column(user_id)" json:"UserId"`
- ProjectID int64 `orm:"column(project_id)" json:"ProjectId"`
- RepoName string `orm:"column(repo_name)"`
- RepoTag string `orm:"column(repo_tag)"`
- GUID string `orm:"column(GUID)" json:"Guid"`
- Operation string `orm:"column(operation)"`
- OpTime time.Time `orm:"column(op_time)"`
- Username string
- Keywords string
-
+ LogID int `orm:"column(log_id)" json:"log_id"`
+ UserID int `orm:"column(user_id)" json:"user_id"`
+ ProjectID int64 `orm:"column(project_id)" json:"project_id"`
+ RepoName string `orm:"column(repo_name)" json:"repo_name"`
+ RepoTag string `orm:"column(repo_tag)" json:"repo_tag"`
+ GUID string `orm:"column(GUID)" json:"guid"`
+ Operation string `orm:"column(operation)" json:"operation"`
+ OpTime time.Time `orm:"column(op_time)" json:"op_time"`
+ Username string `json:"username"`
+ Keywords string `json:"keywords"`
BeginTime time.Time
- BeginTimestamp int64
+ BeginTimestamp int64 `json:"begin_timestamp"`
EndTime time.Time
- EndTimestamp int64
+ EndTimestamp int64 `json:"end_timestamp"`
}
diff --git a/models/project.go b/models/project.go
index f2a374e4c..7f5d54c25 100644
--- a/models/project.go
+++ b/models/project.go
@@ -21,19 +21,19 @@ import (
// Project holds the details of a project.
type Project struct {
- ProjectID int64 `orm:"pk;column(project_id)" json:"ProjectId"`
- OwnerID int `orm:"column(owner_id)" json:"OwnerId"`
- Name string `orm:"column(name)"`
- CreationTime time.Time `orm:"column(creation_time)"`
- CreationTimeStr string
- Deleted int `orm:"column(deleted)"`
- UserID int `json:"UserId"`
- OwnerName string
- Public int `orm:"column(public)"`
+ ProjectID int64 `orm:"column(project_id)" json:"project_id"`
+ OwnerID int `orm:"column(owner_id)" json:"owner_id"`
+ Name string `orm:"column(name)" json:"name"`
+ CreationTime time.Time `orm:"column(creation_time)" json:"creation_time"`
+ CreationTimeStr string `json:"creation_time_str"`
+ Deleted int `orm:"column(deleted)" json:"deleted"`
+ //UserID int `json:"UserId"`
+ OwnerName string `json:"owner_name"`
+ Public int `orm:"column(public)" json:"public"`
//This field does not have correspondent column in DB, this is just for UI to disable button
Togglable bool
UpdateTime time.Time `orm:"update_time" json:"update_time"`
- Role int `json:"role_id"`
+ Role int `json:"current_user_role_id"`
RepoCount int `json:"repo_count"`
}
diff --git a/models/user.go b/models/user.go
index 3f0612c2e..241a25549 100644
--- a/models/user.go
+++ b/models/user.go
@@ -21,20 +21,19 @@ import (
// User holds the details of a user.
type User struct {
- UserID int `orm:"pk;column(user_id)" json:"UserId"`
- Username string `orm:"column(username)" json:"username"`
- Email string `orm:"column(email)" json:"email"`
- Password string `orm:"column(password)" json:"password"`
- Realname string `orm:"column(realname)" json:"realname"`
- Comment string `orm:"column(comment)" json:"comment"`
- Deleted int `orm:"column(deleted)"`
- Rolename string
- RoleID int `json:"RoleId"`
- RoleList []*Role `orm:"rel(m2m)"`
- HasAdminRole int `orm:"column(sysadmin_flag)"`
- ResetUUID string `orm:"column(reset_uuid)" json:"ResetUuid"`
- Salt string `orm:"column(salt)"`
-
+ UserID int `orm:"column(user_id)" json:"user_id"`
+ Username string `orm:"column(username)" json:"username"`
+ Email string `orm:"column(email)" json:"email"`
+ Password string `orm:"column(password)" json:"password"`
+ Realname string `orm:"column(realname)" json:"realname"`
+ Comment string `orm:"column(comment)" json:"comment"`
+ Deleted int `orm:"column(deleted)" json:"deleted"`
+ Rolename string `json:"role_name"`
+ RoleID int `json:"role_id"`
+ // RoleList []Role `json:"role_list"`
+ HasAdminRole int `orm:"column(sysadmin_flag)" json:"has_admin_role"`
+ ResetUUID string `orm:"column(reset_uuid)" json:"reset_uuid"`
+ Salt string `orm:"column(salt)"`
CreationTime time.Time `orm:"creation_time" json:"creation_time"`
UpdateTime time.Time `orm:"update_time" json:"update_time"`
}
diff --git a/static/resources/css/base.css b/static/resources/css/base.css
index 0f8b9bd14..685da65ea 100644
--- a/static/resources/css/base.css
+++ b/static/resources/css/base.css
@@ -13,7 +13,6 @@
limitations under the License.
*/
.footer {
- margin-top: 60px;
width: 100%;
/* Set the fixed height of the footer here */
height: 60px;
diff --git a/static/resources/js/change-password.js b/static/resources/js/change-password.js
index 4c8c2efdc..0a536b7b4 100644
--- a/static/resources/js/change-password.js
+++ b/static/resources/js/change-password.js
@@ -24,7 +24,7 @@ jQuery(function(){
error: function(jqXhr){
if(jqXhr && jqXhr.status == 401){
document.location = "/signIn";
- }
+ }
}
}).exec();
@@ -36,12 +36,12 @@ jQuery(function(){
function bindEnterKey(){
$(document).on("keydown", function(e){
if(e.keyCode == 13){
- e.preventDefault();
- if($("#txtCommonSearch").is(":focus")){
- document.location = "/search?q=" + $("#txtCommonSearch").val();
- }else{
- $("#btnSubmit").trigger("click");
- }
+ e.preventDefault();
+ if($("#txtCommonSearch").is(":focus")){
+ document.location = "/search?q=" + $("#txtCommonSearch").val();
+ }else{
+ $("#btnSubmit").trigger("click");
+ }
}
});
}
@@ -61,35 +61,35 @@ jQuery(function(){
type: "put",
data: {"old_password": oldPassword, "new_password" : password},
beforeSend: function(e){
- unbindEnterKey();
- $("h1").append(spinner.el);
- $("#btnSubmit").prop("disabled", true);
+ unbindEnterKey();
+ $("h1").append(spinner.el);
+ $("#btnSubmit").prop("disabled", true);
},
complete: function(xhr, status){
spinner.stop();
$("#btnSubmit").prop("disabled", false);
if(xhr && xhr.status == 200){
$("#dlgModal")
- .dialogModal({
- "title": i18n.getMessage("title_change_password"),
- "content": i18n.getMessage("change_password_successfully"),
- "callback": function(){
- window.close();
- }
- });
+ .dialogModal({
+ "title": i18n.getMessage("title_change_password"),
+ "content": i18n.getMessage("change_password_successfully"),
+ "callback": function(){
+ window.close();
+ }
+ });
}
},
error: function(jqXhr, status, error){
if(jqXhr && jqXhr.responseText.length){
$("#dlgModal")
- .dialogModal({
- "title": i18n.getMessage("title_change_password"),
- "content": i18n.getMessage(jqXhr.responseText),
- "callback": function(){
- bindEnterKey();
- return;
- }
- });
+ .dialogModal({
+ "title": i18n.getMessage("title_change_password"),
+ "content": i18n.getMessage(jqXhr.responseText),
+ "callback": function(){
+ bindEnterKey();
+ return;
+ }
+ });
}
}
}).exec();
diff --git a/static/resources/js/common.js b/static/resources/js/common.js
index 78cdfc638..f434d0960 100644
--- a/static/resources/js/common.js
+++ b/static/resources/js/common.js
@@ -12,8 +12,9 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
+
var AjaxUtil = function(params){
-
+
this.url = params.url;
this.data = params.data;
this.dataRaw = params.dataRaw;
@@ -31,39 +32,39 @@ AjaxUtil.prototype.exec = function(){
var self = this;
return $.ajax({
- url: self.url,
- contentType: (self.dataRaw ? "application/x-www-form-urlencoded; charset=UTF-8" : "application/json; charset=utf-8"),
- data: JSON.stringify(self.data) || self.dataRaw,
- type: self.type,
- dataType: "json",
- success: function(data, status, xhr){
- if(self.success != null){
- self.success(data, status, xhr);
- }
- },
- complete: function(jqXhr, status) {
- if(self.complete != null){
- self.complete(jqXhr, status);
- }
- },
- error: function(jqXhr){
- if(self.error != null){
- self.error(jqXhr);
- }else{
- var errorMessage = self.errors[jqXhr.status] || jqXhr.responseText;
- if(jqXhr.status == 401){
- var lastUri = location.pathname + location.search;
- if(lastUri != ""){
- document.location = "/signIn?uri=" + encodeURIComponent(lastUri);
- }else{
- document.location = "/signIn";
+ url: self.url,
+ contentType: (self.dataRaw ? "application/x-www-form-urlencoded; charset=UTF-8" : "application/json; charset=utf-8"),
+ data: JSON.stringify(self.data) || self.dataRaw,
+ type: self.type,
+ dataType: "json",
+ success: function(data, status, xhr){
+ if(self.success != null){
+ self.success(data, status, xhr);
+ }
+ },
+ complete: function(jqXhr, status) {
+ if(self.complete != null){
+ self.complete(jqXhr, status);
+ }
+ },
+ error: function(jqXhr){
+ if(self.error != null){
+ self.error(jqXhr);
+ }else{
+ var errorMessage = self.errors[jqXhr.status] || jqXhr.responseText;
+ if(jqXhr.status == 401){
+ var lastUri = location.pathname + location.search;
+ if(lastUri != ""){
+ document.location = "/signIn?uri=" + encodeURIComponent(lastUri);
+ }else{
+ document.location = "/signIn";
+ }
+ }else if($.trim(errorMessage).length > 0){
+ $("#dlgModal").dialogModal({"title": i18n.getMessage("operation_failed"), "content": errorMessage});
}
- }else if($.trim(errorMessage).length > 0){
- $("#dlgModal").dialogModal({"title": i18n.getMessage("operation_failed"), "content": errorMessage});
}
}
- }
- });
+ });
};
var SUPPORT_LANGUAGES = {
@@ -134,7 +135,7 @@ jQuery(function(){
var self = this;
$("#dlgLabel", self).text(settings.title);
-
+
if(options.text){
$("#dlgBody", self).html(settings.content);
}else if(typeof settings.content == "object"){
@@ -142,9 +143,9 @@ jQuery(function(){
var lines = ['
');
$("#dlgBody", self).html(lines.join(""));
@@ -154,8 +155,13 @@ jQuery(function(){
}
if(settings.callback != null){
- $("#dlgConfirm").on("click", function(){
- settings.callback();
+ var hasEntered = false;
+ $("#dlgConfirm").on("click", function(e){
+ if(!hasEntered) {
+ hasEntered = true;
+ settings.callback();
+
+ }
});
}
$(self).modal('show');
diff --git a/static/resources/js/forgot-password.js b/static/resources/js/forgot-password.js
index b7c4be9e6..d6fdea319 100644
--- a/static/resources/js/forgot-password.js
+++ b/static/resources/js/forgot-password.js
@@ -13,26 +13,26 @@
limitations under the License.
*/
jQuery(function(){
-
+
$("#divErrMsg").css({"display": "none"});
validateOptions.Items = ["#EmailF"];
function bindEnterKey(){
$(document).on("keydown", function(e){
if(e.keyCode == 13){
- e.preventDefault();
- if($("#txtCommonSearch").is(":focus")){
- document.location = "/search?q=" + $("#txtCommonSearch").val();
- }else{
- $("#btnSubmit").trigger("click");
- }
+ e.preventDefault();
+ if($("#txtCommonSearch").is(":focus")){
+ document.location = "/search?q=" + $("#txtCommonSearch").val();
+ }else{
+ $("#btnSubmit").trigger("click");
+ }
}
});
}
function unbindEnterKey(){
$(document).off("keydown");
}
- bindEnterKey();
+ bindEnterKey();
var spinner = new Spinner({scale:1}).spin();
$("#btnSubmit").on("click", function(){
@@ -44,20 +44,20 @@ jQuery(function(){
"type": "get",
"data": {"username": username, "email": email},
"beforeSend": function(e){
- unbindEnterKey();
- $("h1").append(spinner.el);
- $("#btnSubmit").prop("disabled", true);
+ unbindEnterKey();
+ $("h1").append(spinner.el);
+ $("#btnSubmit").prop("disabled", true);
},
"success": function(data, status, xhr){
if(xhr && xhr.status == 200){
$("#dlgModal")
- .dialogModal({
- "title": i18n.getMessage("title_forgot_password"),
- "content": i18n.getMessage("email_has_been_sent"),
- "callback": function(){
- document.location="/";
- }
- });
+ .dialogModal({
+ "title": i18n.getMessage("title_forgot_password"),
+ "content": i18n.getMessage("email_has_been_sent"),
+ "callback": function(){
+ document.location="/";
+ }
+ });
}
},
@@ -68,14 +68,14 @@ jQuery(function(){
"error": function(jqXhr, status, error){
if(jqXhr){
$("#dlgModal")
- .dialogModal({
- "title": i18n.getMessage("title_forgot_password"),
- "content": i18n.getMessage(jqXhr.responseText),
- "callback": function(){
- bindEnterKey();
- return;
- }
- });
+ .dialogModal({
+ "title": i18n.getMessage("title_forgot_password"),
+ "content": i18n.getMessage(jqXhr.responseText),
+ "callback": function(){
+ bindEnterKey();
+ return;
+ }
+ });
}
}
});
diff --git a/static/resources/js/header-login.js b/static/resources/js/header-login.js
index 8e1a6e35e..1bd5cda0d 100644
--- a/static/resources/js/header-login.js
+++ b/static/resources/js/header-login.js
@@ -13,20 +13,20 @@
limitations under the License.
*/
jQuery(function(){
- $("#btnSignUp").css({"visibility": "visible"});
+ $("#btnSignUp").css({"visibility": "visible"});
$(document).on("keydown", function(e){
if(e.keyCode == 13){
e.preventDefault();
if($("#txtCommonSearch").is(":focus")){
- document.location = "/search?q=" + $("#txtCommonSearch").val();
+ document.location = "/search?q=" + $("#txtCommonSearch").val();
}
}
});
$("#btnSignIn").on("click", function(){
document.location = "/signIn";
});
- $("#btnSignUp").on("click", function(){
+ $("#btnSignUp").on("click", function(){
document.location = "/register";
});
});
\ No newline at end of file
diff --git a/static/resources/js/item-detail.js b/static/resources/js/item-detail.js
index c63b1a69b..bfab81536 100644
--- a/static/resources/js/item-detail.js
+++ b/static/resources/js/item-detail.js
@@ -23,461 +23,451 @@ jQuery(function(){
if(jqXhr.status == 403){
return false;
}
- }
+ }
}
}).exec()
- ).then(function(){
- noNeedToLoginCallback();
- needToLoginCallback();
- }).fail(function(){
- noNeedToLoginCallback();
- });
-
- function noNeedToLoginCallback(){
-
- $("#tabItemDetail a:first").tab("show");
- $("#btnFilterOption button:first").addClass("active");
- $("#divErrMsg").hide();
-
- if($("#public").val() == 1){
- $("#tabItemDetail li:eq(1)").hide();
- $("#tabItemDetail li:eq(2)").hide();
- }
-
- listRepo($("#repoName").val());
-
- function listRepo(repoName){
+ ).then(function(){
+ noNeedToLoginCallback();
+ needToLoginCallback();
+ }).fail(function(){
+ noNeedToLoginCallback();
+ });
+ function noNeedToLoginCallback(){
+
+ $("#tabItemDetail a:first").tab("show");
+ $("#btnFilterOption button:first").addClass("active");
$("#divErrMsg").hide();
+
+ if($("#public").val() == 1){
+ $("#tabItemDetail li:eq(1)").hide();
+ $("#tabItemDetail li:eq(2)").hide();
+ }
+
+ listRepo($("#repoName").val());
+
+ function listRepo(repoName){
+
+ $("#divErrMsg").hide();
- new AjaxUtil({
- url: "/api/repositories?project_id=" + $("#projectId").val() + "&q=" + repoName,
- type: "get",
- success: function(data, status, xhr){
- if(xhr && xhr.status == 200){
- $("#accordionRepo").children().remove();
- if(data == null){
- $("#divErrMsg").show();
- $("#divErrMsg center").html(i18n.getMessage("no_repo_exists"));
- return;
- }
- $.each(data, function(i, e){
- var targetId = e.replace(/\//g, "------").replace(/\./g, "---");
- var row = '' +
+ new AjaxUtil({
+ url: "/api/repositories?project_id=" + $("#projectId").val() + "&q=" + repoName,
+ type: "get",
+ success: function(data, status, xhr){
+ if(xhr && xhr.status == 200){
+ $("#accordionRepo").children().remove();
+ if(data == null){
+ $("#divErrMsg").show();
+ $("#divErrMsg center").html(i18n.getMessage("no_repo_exists"));
+ return;
+ }
+ $.each(data, function(i, e){
+ var targetId = e.replace(/\//g, "------").replace(/\./g, "---");
+ var row = '
' +
'
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '' +
- '' +
- ' ' + i18n.getMessage("tag")+ ' ' +
- ' ' + i18n.getMessage("pull_command") + ' ' +
- ' ' +
- ' ' +
- '' +
- ' ' +
- '
'
- '
' +
- '
' +
- '
' +
- '
';
- $("#accordionRepo").append(row);
- });
- if(repoName != ""){
- $("#txtRepoName").val(repoName);
- $("#accordionRepo #heading0 a").trigger("click");
+ '
' +
+ '
' +
+ '' +
+ '
' +
+ '
' +
+ '
' +
+ '' +
+ '' +
+ ' ' + i18n.getMessage("tag")+ ' ' +
+ ' ' + i18n.getMessage("pull_command") + ' ' +
+ ' ' +
+ ' ' +
+ '' +
+ ' ' +
+ '
'
+ '
' +
+ '
' +
+ '
' +
+ '';
+ $("#accordionRepo").append(row);
+ });
+ if(repoName != ""){
+ $("#txtRepoName").val(repoName);
+ $("#accordionRepo #heading0 a").trigger("click");
+ }
}
}
- }
- }).exec();
- }
- $("#btnSearchRepo").on("click", function(){
- listRepo($.trim($("#txtRepoName").val()));
- });
-
- $('#accordionRepo').on('show.bs.collapse', function (e) {
- $('#accordionRepo .in').collapse('hide');
- var targetId = $(e.target).attr("targetId");
- var repoName = targetId.replace(/[-]{6}/g, "/").replace(/[-]{3}/g, '.');
- new AjaxUtil({
- url: "/api/repositories/tags?repo_name=" + repoName,
- type: "get",
- success: function(data, status, xhr){
- $('#' + targetId +' table tbody tr').remove();
- var row = [];
- for(var i in data){
- var tagName = data[i];
- row.push('' + tagName + ' ');
- }
- $('#' + targetId +' table tbody').append(row.join(""));
- $('#' + targetId +' table tbody tr a').on("click", function(e){
- var imageId = $(this).attr("imageId");
- var repoName = $(this).attr("repoName");
- new AjaxUtil({
- url: "/api/repositories/manifests?repo_name=" + repoName + "&tag=" + imageId,
- type: "get",
- success: function(data, status, xhr){
- if(data){
- for(var i in data){
- if(data[i] == ""){
- data[i] = "N/A";
- }
- }
- data.Created = moment(new Date(data.Created)).format("YYYY-MM-DD HH:mm:ss");
-
- $("#dlgModal").dialogModal({"title": i18n.getMessage("image_details"), "content": data});
- }
- }
- }).exec();
- });
- }
- }).exec();
- });
- }
-
- function needToLoginCallback(){
-
- var hasAuthorization = false;
-
- $.when(
- new AjaxUtil({
- url: "/api/projects/" + $("#projectId").val() + "/members/current",
- type: "get",
- success: function(data, status, xhr){
- if(xhr && xhr.status == 200 && data.roles != null && data.roles.length > 0){
- hasAuthorization = true;
- }
- }
- }).exec())
- .done(function(){
-
- if(!hasAuthorization) return false;
-
- $("#tabItemDetail a:eq(1)").css({"visibility": "visible"});
- $("#tabItemDetail a:eq(2)").css({"visibility": "visible"});
-
- $(".glyphicon .glyphicon-pencil", "#tblUser").on("click", function(e){
- $("#txtUserName").hide();
- $("#lblUserName").show();
- $("#dlgUserTitle").text(i18n.getMessage("edit_members"));
- });
-
- $("#btnAddUser").on("click", function(){
- $("#operationType").val("add");
- $("#spnSearch").show();
- $("#txtUserName").prop("disabled", false)
- $("#txtUserName").val("");
- $("#lstRole input[name=chooseRole]:radio").prop("checked", false);
- $("#dlgUserTitle").text(i18n.getMessage("add_members"));
- });
-
- $("#btnSave").on("click", function(){
-
- var username = $("#txtUserName").val();
- if($.trim(username).length == 0){
- $("#dlgModal").dialogModal({"title": i18n.getMessage("add_member_failed"), "content": i18n.getMessage("please_input_username")});
- return;
- }
- var projectId = $("#projectId").val();
- var operationType = $("#operationType").val();
- var userId = $("#editUserId").val();
-
- var checkedRole = $("#lstRole input[name='chooseRole']:checked")
- if(checkedRole.length == 0){
- $("#dlgModal").dialogModal({"title": i18n.getMessage("add_member_failed"), "content": i18n.getMessage("please_assign_a_role_to_user")});
- return;
- }
-
- var checkedRoleItemList = [];
- $.each(checkedRole, function(i, e){
- checkedRoleItemList.push(new Number($(this).val()));
- });
-
- var ajaxOpts = {};
- if(operationType == "add"){
- ajaxOpts.url = "/api/projects/" + projectId + "/members/";
- ajaxOpts.type = "post";
- ajaxOpts.data = {"roles" : checkedRoleItemList, "user_name": username};
- }else if(operationType == "edit"){
- ajaxOpts.url = "/api/projects/" + projectId + "/members/" + userId;
- ajaxOpts.type = "put";
- ajaxOpts.data = {"roles" : checkedRoleItemList};
- }
-
- new AjaxUtil({
- url: ajaxOpts.url,
- data: ajaxOpts.data,
- type: ajaxOpts.type,
- complete: function(jqXhr, status){
- if(jqXhr && jqXhr.status == 200){
- $("#btnCancel").trigger("click");
- listUser(null);
- }
- },
- errors: {
- 404: i18n.getMessage("user_id_does_not_exist"),
- 409: i18n.getMessage("user_id_exists"),
- 403: i18n.getMessage("insufficient_privileges")
- }
- }).exec();
- });
-
- var name_mapping = {
- "projectAdmin": "Project Admin",
- "developer": "Developer",
- "guest": "Guest"
- }
-
- function listUserByProjectCallback(userList){
- var loginedUserId = $("#userId").val();
- var loginedUserRoleId = $("#roleId").val();
- var ownerId = $("#ownerId").val();
-
- $("#tblUser tbody tr").remove();
- for(var i = 0; i < userList.length; ){
-
- var userId = userList[i].UserId;
- var roleId = userList[i].RoleId;
- var username = userList[i].username;
- var roleNameList = [];
-
- for(var j = i; j < userList.length; i++, j++){
- if(userList[j].UserId == userId){
- roleNameList.push(name_mapping[userList[j].Rolename]);
- }else{
- break;
- }
- }
-
- var row = '' +
- '' + username + ' ' +
- '' + roleNameList.join(",") + ' ' +
- '';
- var isShowOperations = true;
- if(loginedUserRoleId >= 3 /*role: developer guest*/){
- isShowOperations = false;
- }else if(ownerId == userId){
- isShowOperations = false;
- }else if (loginedUserId == userId){
- isShowOperations = false;
- }
- if(isShowOperations){
- row += ' ' +
- ' ';
- }
-
- row += ' ';
- $("#tblUser tbody").append(row);
-
- }
- }
-
- function searchAccessLogCallback(LogList){
- $("#tabOperationLog tbody tr").remove();
- $.each(LogList || [], function(i, e){
- $("#tabOperationLog tbody").append(
- '' +
- '' + e.Username + ' ' +
- '' + e.RepoName + ' ' +
- '' + e.RepoTag + ' ' +
- '' + e.Operation + ' ' +
- '' + moment(new Date(e.OpTime)).format("YYYY-MM-DD HH:mm:ss") + ' ' +
- ' ');
- });
- }
-
- function getUserRoleCallback(userId){
- new AjaxUtil({
- url: "/api/projects/" + $("#projectId").val() + "/members/" + userId,
- type: "get",
- success: function(data, status, xhr){
- var user = data;
- $("#operationType").val("edit");
- $("#editUserId").val(user.user_id);
- $("#spnSearch").hide();
- $("#txtUserName").val(user.user_name);
- $("#txtUserName").prop("disabled", true);
- $("#btnSave").removeClass("disabled");
- $("#dlgUserTitle").text(i18n.getMessage("edit_members"));
- $("#lstRole input[name=chooseRole]:radio").not('[value=' + user.role_id + ']').prop("checked", false)
- $.each(user.roles, function(i, e){
- $("#lstRole input[name=chooseRole]:radio").filter('[value=' + e.role_id + ']').prop("checked", "checked");
- });
- }
}).exec();
}
- function listUser(username){
- $.when(
- new AjaxUtil({
- url: "/api/projects/" + $("#projectId").val() + "/members?username=" + (username == null ? "" : username),
- type: "get",
- errors: {
- 403: ""
- },
- success: function(data, status, xhr){
- return data || [];
- }
- }).exec()
- ).done(function(userList){
- listUserByProjectCallback(userList || []);
- $("#tblUser .glyphicon-pencil").on("click", function(e){
- var userId = $(this).attr("userid")
- getUserRoleCallback(userId);
- });
- $("#tblUser .glyphicon-trash").on("click", function(){
- var userId = $(this).attr("userid");
- new AjaxUtil({
- url: "/api/projects/" + $("#projectId").val() + "/members/" + userId,
- type: "delete",
- complete: function(jqXhr, status){
- if(jqXhr && jqXhr.status == 200){
- listUser(null);
- }
- }
- }).exec();
- });
- });
- }
- listUser(null);
- listOperationLogs();
-
- function listOperationLogs(){
- var projectId = $("#projectId").val();
-
- $.when(
- new AjaxUtil({
- url : "/api/projects/" + projectId + "/logs/filter",
- data: {},
- type: "post",
- success: function(data){
- return data || [];
- }
- }).exec()
- ).done(function(operationLogs){
- searchAccessLogCallback(operationLogs);
- });
- }
-
- $("#btnSearchUser").on("click", function(){
- var username = $("#txtSearchUser").val();
- if($.trim(username).length == 0){
- username = null;
- }
- listUser(username);
+ $("#btnSearchRepo").on("click", function(){
+ listRepo($.trim($("#txtRepoName").val()));
});
- 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(),
+ $('#accordionRepo').on('show.bs.collapse', function (e) {
+ $('#accordionRepo .in').collapse('hide');
+ var targetId = $(e.target).attr("targetId");
+ var repoName = targetId.replace(/[-]{6}/g, "/").replace(/[-]{3}/g, ".");
+ new AjaxUtil({
+ url: "/api/repositories/tags?repo_name=" + repoName,
+ type: "get",
+ success: function(data, status, xhr){
+ $('#' + targetId +' table tbody tr').remove();
+ var row = [];
+ for(var i in data){
+ var tagName = data[i]
+ row.push('' + tagName + ' ');
+ }
+ $('#' + targetId +' table tbody').append(row.join(""));
+ $('#' + targetId +' table tbody tr a').on("click", function(e){
+ var imageId = $(this).attr("imageId");
+ var repoName = $(this).attr("repoName");
+ new AjaxUtil({
+ url: "/api/repositories/manifests?repo_name=" + repoName + "&tag=" + imageId,
+ type: "get",
+ success: function(data, status, xhr){
+ if(data){
+ for(var i in data){
+ if(data[i] == ""){
+ data[i] = "N/A";
+ }
+ }
+ data.Created = moment(new Date(data.Created)).format("YYYY-MM-DD HH:mm:ss");
+ $("#dlgModal").dialogModal({"title": i18n.getMessage("image_details"), "content": data});
+ }
+ }
+ }).exec();
+ });
+ }
+ }).exec();
+ });
+ }
+
+ function needToLoginCallback(){
+
+ var hasAuthorization = false;
+
+ $.when(
+ new AjaxUtil({
+ url: "/api/projects/" + $("#projectId").val() + "/members/current",
+ type: "get",
+ success: function(data, status, xhr){
+ if(xhr && xhr.status == 200 && data.roles != null && data.roles.length > 0){
+ hasAuthorization = true;
+ }
+ }
+ }).exec())
+ .done(function(){
+
+ if(!hasAuthorization) return false;
+
+ $("#tabItemDetail a:eq(1)").css({"visibility": "visible"});
+ $("#tabItemDetail a:eq(2)").css({"visibility": "visible"});
+
+ $(".glyphicon .glyphicon-pencil", "#tblUser").on("click", function(e){
+ $("#txtUserName").hide();
+ $("#lblUserName").show();
+ $("#dlgUserTitle").text(i18n.getMessage("edit_members"));
+ });
+
+ $("#btnAddUser").on("click", function(){
+ $("#operationType").val("add");
+ $("#spnSearch").show();
+ $("#txtUserName").prop("disabled", false)
+ $("#txtUserName").val("");
+ $("#lstRole input[name=chooseRole]:radio").prop("checked", false);
+ $("#dlgUserTitle").text(i18n.getMessage("add_members"));
+ });
+
+ $("#btnSave").on("click", function(){
+
+ var username = $("#txtUserName").val();
+ if($.trim(username).length == 0){
+ $("#dlgModal").dialogModal({"title": i18n.getMessage("add_member_failed"), "content": i18n.getMessage("please_input_username")});
+ return;
+ }
+ var projectId = $("#projectId").val();
+ var operationType = $("#operationType").val();
+ var userId = $("#editUserId").val();
+
+ var checkedRole = $("#lstRole input[name='chooseRole']:checked")
+ if(checkedRole.length == 0){
+ $("#dlgModal").dialogModal({"title": i18n.getMessage("add_member_failed"), "content": i18n.getMessage("please_assign_a_role_to_user")});
+ return;
+ }
+
+ var checkedRoleItemList = [];
+ $.each(checkedRole, function(i, e){
+ checkedRoleItemList.push(new Number($(this).val()));
+ });
+
+ var ajaxOpts = {};
+ if(operationType == "add"){
+ ajaxOpts.url = "/api/projects/" + projectId + "/members/";
+ ajaxOpts.type = "post";
+ ajaxOpts.data = {"roles" : checkedRoleItemList, "username": username};
+ }else if(operationType == "edit"){
+ ajaxOpts.url = "/api/projects/" + projectId + "/members/" + userId;
+ ajaxOpts.type = "put";
+ ajaxOpts.data = {"roles" : checkedRoleItemList};
+ }
+
+ new AjaxUtil({
+ url: ajaxOpts.url,
+ data: ajaxOpts.data,
+ type: ajaxOpts.type,
+ complete: function(jqXhr, status){
+ if(jqXhr && jqXhr.status == 200){
+ $("#btnCancel").trigger("click");
+ listUser(null);
+ }
+ },
+ errors: {
+ 404: i18n.getMessage("user_id_does_not_exist"),
+ 409: i18n.getMessage("user_id_exists"),
+ 403: i18n.getMessage("insufficient_privileges")
+ }
+ }).exec();
+ });
+
+ var name_mapping = {
+ "projectAdmin": "Project Admin",
+ "developer": "Developer",
+ "guest": "Guest"
+ }
+
+ function listUserByProjectCallback(userList){
+ var loginedUserId = $("#userId").val();
+ var loginedUserRoleId = $("#roleId").val();
+ var ownerId = $("#ownerId").val();
+
+ $("#tblUser tbody tr").remove();
+ for(var i = 0; i < userList.length; i++){
+
+ var userId = userList[i].user_id;
+ var roleId = userList[i].role_id;
+ var username = userList[i].username;
+
+ var row = '' +
+ '' + username + ' ' +
+ '' + name_mapping[userList[i].role_name] + ' ' +
+ '';
+ var isShowOperations = true;
+ if(loginedUserRoleId >= 3 /*role: developer guest*/){
+ isShowOperations = false;
+ }else if(ownerId == userId){
+ isShowOperations = false;
+ }else if (loginedUserId == userId){
+ isShowOperations = false;
+ }
+ if(isShowOperations){
+ row += ' ' +
+ ' ';
+ }
+
+ row += ' ';
+ $("#tblUser tbody").append(row);
+
+ }
+ }
+
+ function searchAccessLogCallback(LogList){
+ $("#tabOperationLog tbody tr").remove();
+ $.each(LogList || [], function(i, e){
+ $("#tabOperationLog tbody").append(
+ '' +
+ '' + e.username + ' ' +
+ '' + e.repo_name + ' ' +
+ '' + e.repo_tag + ' ' +
+ '' + e.operation + ' ' +
+ '' + moment(new Date(e.op_time)).format("YYYY-MM-DD HH:mm:ss") + ' ' +
+ ' ');
+ });
+ }
+
+ function getUserRoleCallback(userId){
+ new AjaxUtil({
+ url: "/api/projects/" + $("#projectId").val() + "/members/" + userId,
+ type: "get",
+ success: function(data, status, xhr){
+ var user = data;
+ $("#operationType").val("edit");
+ $("#editUserId").val(user.user_id);
+ $("#spnSearch").hide();
+ $("#txtUserName").val(user.username);
+ $("#txtUserName").prop("disabled", true);
+ $("#btnSave").removeClass("disabled");
+ $("#dlgUserTitle").text(i18n.getMessage("edit_members"));
+ $("#lstRole input[name=chooseRole]:radio").not('[value=' + user.role_id + ']').prop("checked", false)
+ $.each(user.roles, function(i, e){
+ $("#lstRole input[name=chooseRole]:radio").filter('[value=' + e.role_id + ']').prop("checked", "checked");
+ });
+ }
+ }).exec();
+ }
+ function listUser(username){
+ $.when(
+ new AjaxUtil({
+ url: "/api/projects/" + $("#projectId").val() + "/members?username=" + (username == null ? "" : username),
+ type: "get",
+ errors: {
+ 403: ""
+ },
+ success: function(data, status, xhr){
+ return data || [];
+ }
+ }).exec()
+ ).done(function(userList){
+ listUserByProjectCallback(userList || []);
+ $("#tblUser .glyphicon-pencil").on("click", function(e){
+ var userId = $(this).attr("userid")
+ getUserRoleCallback(userId);
+ });
+ $("#tblUser .glyphicon-trash").on("click", function(){
+ var userId = $(this).attr("userid");
+ new AjaxUtil({
+ url: "/api/projects/" + $("#projectId").val() + "/members/" + userId,
+ type: "delete",
+ complete: function(jqXhr, status){
+ if(jqXhr && jqXhr.status == 200){
+ listUser(null);
+ }
+ }
+ }).exec();
+ });
+ });
+ }
+ listUser(null);
+ listOperationLogs();
+
+ function listOperationLogs(){
+ var projectId = $("#projectId").val();
+
+ $.when(
+ new AjaxUtil({
+ url : "/api/projects/" + projectId + "/logs/filter",
+ data: {},
+ type: "post",
+ success: function(data){
+ return data || [];
+ }
+ }).exec()
+ ).done(function(operationLogs){
+ searchAccessLogCallback(operationLogs);
+ });
+ }
+
+ $("#btnSearchUser").on("click", function(){
+ var username = $("#txtSearchUser").val();
+ if($.trim(username).length == 0){
+ username = null;
+ }
+ 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 beginTimestamp = 0;
- var endTimestamp = 0;
-
- if($("#begindatepicker").val() != ""){
- beginTimestamp = toUTCSeconds($("#begindatepicker").val(), 0, 0, 0);
- }
- if($("#enddatepicker").val() != ""){
- endTimestamp = toUTCSeconds($("#enddatepicker").val(), 23, 59, 59);
- }
-
- new AjaxUtil({
- url: "/api/projects/" + projectId + "/logs/filter",
- data:{"username":username, "project_id" : projectId, "keywords" : getKeyWords() , "beginTimestamp" : beginTimestamp, "endTimestamp" : endTimestamp},
- type: "post",
- success: function(data, status, xhr){
- if(xhr && xhr.status == 200){
- searchAccessLogCallback(data);
+ return utcTime.getTime() / 1000;
}
- }
- }).exec();
- });
-
- $("#spnFilterOption input[name=chkAll]").on("click", function(){
- $("#spnFilterOption input[name=chkOperation]").prop("checked", $(this).prop("checked"));
- });
-
- $("#spnFilterOption input[name=chkOperation]").on("click", function(){
- if(!$(this).prop("checked")){
- $("#spnFilterOption input[name=chkAll]").prop("checked", false);
- }
-
- var selectedAll = true;
-
- $("#spnFilterOption input[name=chkOperation]").each(function(i, e){
- if(!$(e).prop("checked")){
- selectedAll = false;
- }
- });
-
- if(selectedAll){
- $("#spnFilterOption input[name=chkAll]").prop("checked", true);
- }
- });
-
- function getKeyWords(){
- var keywords = "";
- var checkedItemList=$("#spnFilterOption input[name=chkOperation]:checked");
- var keywords = [];
- $.each(checkedItemList, function(i, e){
- var itemValue = $(e).val();
- if(itemValue == "others" && $.trim($("#txtOthers").val()).length > 0){
- keywords.push($("#txtOthers").val());
- }else{
- keywords.push($(e).val());
- }
- });
- return keywords.join("/");
- }
-
- $('#datetimepicker1').datetimepicker({
- locale: i18n.getLocale(),
- ignoreReadonly: true,
- format: 'L',
- showClear: true
- });
- $('#datetimepicker2').datetimepicker({
- locale: i18n.getLocale(),
- ignoreReadonly: true,
- format: 'L',
- showClear: true
- });
- });
- }
-
- $(document).on("keydown", function(e){
- if(e.keyCode == 13){
- e.preventDefault();
- if($("#tabItemDetail li:eq(0)").is(":focus") || $("#txtRepoName").is(":focus")){
- $("#btnSearchRepo").trigger("click");
- }else if($("#tabItemDetail li:eq(1)").is(":focus") || $("#txtSearchUser").is(":focus")){
- $("#btnSearchUser").trigger("click");
- }else if($("#tabItemDetail li:eq(2)").is(":focus") || $("#txtSearchUserName").is(":focus")){
- $("#btnFilterLog").trigger("click");
- }else if($("#txtUserName").is(":focus") || $("#lstRole :radio").is(":focus")){
- $("#btnSave").trigger("click");
- }
+
+ $("#btnFilterLog").on("click", function(){
+
+ var projectId = $("#projectId").val();
+ var username = $("#txtSearchUserName").val();
+
+ var beginTimestamp = 0;
+ var endTimestamp = 0;
+
+ if($("#begindatepicker").val() != ""){
+ beginTimestamp = toUTCSeconds($("#begindatepicker").val(), 0, 0, 0);
+ }
+ if($("#enddatepicker").val() != ""){
+ endTimestamp = toUTCSeconds($("#enddatepicker").val(), 23, 59, 59);
+ }
+
+ new AjaxUtil({
+ url: "/api/projects/" + projectId + "/logs/filter",
+ data:{"username":username, "project_id" : Number(projectId), "keywords" : getKeyWords() , "begin_timestamp" : beginTimestamp, "end_timestamp" : endTimestamp},
+ type: "post",
+ success: function(data, status, xhr){
+ if(xhr && xhr.status == 200){
+ searchAccessLogCallback(data);
+ }
+ }
+ }).exec();
+ });
+
+ $("#spnFilterOption input[name=chkAll]").on("click", function(){
+ $("#spnFilterOption input[name=chkOperation]").prop("checked", $(this).prop("checked"));
+ });
+
+ $("#spnFilterOption input[name=chkOperation]").on("click", function(){
+ if(!$(this).prop("checked")){
+ $("#spnFilterOption input[name=chkAll]").prop("checked", false);
+ }
+
+ var selectedAll = true;
+
+ $("#spnFilterOption input[name=chkOperation]").each(function(i, e){
+ if(!$(e).prop("checked")){
+ selectedAll = false;
+ }
+ });
+
+ if(selectedAll){
+ $("#spnFilterOption input[name=chkAll]").prop("checked", true);
+ }
+ });
+
+ function getKeyWords(){
+ var keywords = "";
+ var checkedItemList=$("#spnFilterOption input[name=chkOperation]:checked");
+ var keywords = [];
+ $.each(checkedItemList, function(i, e){
+ var itemValue = $(e).val();
+ if(itemValue == "others" && $.trim($("#txtOthers").val()).length > 0){
+ keywords.push($("#txtOthers").val());
+ }else{
+ keywords.push($(e).val());
+ }
+ });
+ return keywords.join("/");
+ }
+
+ $('#datetimepicker1').datetimepicker({
+ locale: i18n.getLocale(),
+ ignoreReadonly: true,
+ format: 'L',
+ showClear: true
+ });
+ $('#datetimepicker2').datetimepicker({
+ locale: i18n.getLocale(),
+ ignoreReadonly: true,
+ format: 'L',
+ showClear: true
+ });
+ });
+}
+
+$(document).on("keydown", function(e){
+ if(e.keyCode == 13){
+ e.preventDefault();
+ if($("#tabItemDetail li:eq(0)").is(":focus") || $("#txtRepoName").is(":focus")){
+ $("#btnSearchRepo").trigger("click");
+ }else if($("#tabItemDetail li:eq(1)").is(":focus") || $("#txtSearchUser").is(":focus")){
+ $("#btnSearchUser").trigger("click");
+ }else if($("#tabItemDetail li:eq(2)").is(":focus") || $("#txtSearchUserName").is(":focus")){
+ $("#btnFilterLog").trigger("click");
+ }else if($("#txtUserName").is(":focus") || $("#lstRole :radio").is(":focus")){
+ $("#btnSave").trigger("click");
}
- });
-})
+ }
+});
+})
\ No newline at end of file
diff --git a/static/resources/js/login.js b/static/resources/js/login.js
index 9b0bfda2b..21c0b6cd2 100644
--- a/static/resources/js/login.js
+++ b/static/resources/js/login.js
@@ -24,7 +24,7 @@ jQuery(function(){
},
error: function(jqXhr){
if(jqXhr.status == 401)
- return false;
+ return false;
}
}).exec();
diff --git a/static/resources/js/project.js b/static/resources/js/project.js
index 97da2d6f9..427aa39dd 100644
--- a/static/resources/js/project.js
+++ b/static/resources/js/project.js
@@ -13,13 +13,13 @@
limitations under the License.
*/
jQuery(function(){
-
+
new AjaxUtil({
url: "/api/users/current",
type: "get",
success: function(data, status, xhr){
if(xhr && xhr.status == 200){
- if(data.HasAdminRole == 1) {
+ if(data.has_admin_role == 1) {
renderForAdminRole();
}
renderForAnyRole();
@@ -29,57 +29,57 @@ jQuery(function(){
function renderForAnyRole(){
$("#tabProject a:first").tab("show");
-
+
$(document).on("keydown", function(e){
if(e.keyCode == 13){
- e.preventDefault();
- if($("#tabProject li:eq(0)").is(":focus") || $("#txtSearchProject").is(":focus")){
- $("#btnSearch").trigger("click");
- }else if($("#tabProject li:eq(1)").is(":focus") || $("#txtSearchPublicProjects").is(":focus")){
- $("#btnSearchPublicProjects").trigger("click");
- }else if($("#tabProject li:eq(1)").is(":focus") || $("#txtSearchUsername").is(":focus")){
- $("#btnSearchUsername").trigger("click");
- }else if($("#dlgAddProject").is(":focus") || $("#projectName").is(":focus")){
- $("#btnSave").trigger("click");
- }
+ e.preventDefault();
+ if($("#tabProject li:eq(0)").is(":focus") || $("#txtSearchProject").is(":focus")){
+ $("#btnSearch").trigger("click");
+ }else if($("#tabProject li:eq(1)").is(":focus") || $("#txtSearchPublicProjects").is(":focus")){
+ $("#btnSearchPublicProjects").trigger("click");
+ }else if($("#tabProject li:eq(1)").is(":focus") || $("#txtSearchUsername").is(":focus")){
+ $("#btnSearchUsername").trigger("click");
+ }else if($("#dlgAddProject").is(":focus") || $("#projectName").is(":focus")){
+ $("#btnSave").trigger("click");
+ }
}
});
-
+
function listProject(projectName, isPublic){
currentPublic = isPublic;
$.when(
new AjaxUtil({
- url: "/api/projects?is_public=" + isPublic + "&project_name=" + (projectName == null ? "" : projectName) + "×tamp=" + new Date().getTime(),
- type: "get",
- success: function(data, status, xhr){
- $("#tblProject tbody tr").remove();
- $.each(data || [], function(i, e){
- var row = '' +
- '' + e.Name + ' ' +
- '' + moment(new Date(e.CreationTime)).format("YYYY-MM-DD HH:mm:ss") + ' ';
- if(e.Public == 1 && e.Togglable){
- row += '' + i18n.getMessage("button_on")+ ' '
- } else if (e.Public == 1) {
- row += '' + i18n.getMessage("button_on")+ ' ';
- } else if (e.Public == 0 && e.Togglable) {
- row += '' + i18n.getMessage("button_off")+ ' ';
- } else if (e.Public == 0) {
- row += '' + i18n.getMessage("button_off")+ ' ';
- row += ' ';
- }
- $("#tblProject tbody").append(row);
- });
- }
- }).exec())
+ url: "/api/projects?is_public=" + isPublic + "&project_name=" + (projectName == null ? "" : projectName) + "×tamp=" + new Date().getTime(),
+ type: "get",
+ success: function(data, status, xhr){
+ $("#tblProject tbody tr").remove();
+ $.each(data || [], function(i, e){
+ var row = '' +
+ '' + e.name + ' ' +
+ '' + moment(new Date(e.creation_time)).format("YYYY-MM-DD HH:mm:ss") + ' ';
+ if(e.public == 1 && e.Togglable){
+ row += '' + i18n.getMessage("button_on")+ ' '
+ } else if (e.public == 1) {
+ row += '' + i18n.getMessage("button_on")+ ' ';
+ } else if (e.public == 0 && e.Togglable) {
+ row += '' + i18n.getMessage("button_off")+ ' ';
+ } else if (e.public == 0) {
+ row += '' + i18n.getMessage("button_off")+ ' ';
+ row += ' ';
+ }
+ $("#tblProject tbody").append(row);
+ });
+ }
+ }).exec())
.done(function() {
- $("#tblProject tbody tr :button").on("click", function(){
- var projectId = $(this).attr("projectid");
- var self = this;
- new AjaxUtil({
- url: "/api/projects/" + projectId,
- data: {"public": ($(self).hasClass("btn-success") ? false : true)},
- type: "put",
- complete: function(jqXhr, status) {
+ $("#tblProject tbody tr :button").on("click", function(){
+ var projectId = $(this).attr("projectid");
+ var self = this;
+ new AjaxUtil({
+ url: "/api/projects/" + projectId,
+ data: {"public": ($(self).hasClass("btn-success") ? false : true)},
+ type: "put",
+ complete: function(jqXhr, status) {
if($(self).hasClass("btn-success")){
$(self).removeClass("btn-success").addClass("btn-danger");
$(self).html(i18n.getMessage("button_off"));
@@ -88,9 +88,9 @@ jQuery(function(){
$(self).html(i18n.getMessage("button_on"));
}
}
- }).exec();
- });
- });
+ }).exec();
+ });
+ });
}
listProject(null, 0);
var currentPublic = 0;
@@ -119,7 +119,7 @@ jQuery(function(){
$("#projectName").val("");
$("#projectName").parent().addClass("has-feedback");
$("#projectName").siblings("span").removeClass("glyphicon-warning-sign").removeClass("glyphicon-ok");
- $("#isPublic").prop('checked', false);
+ $("#isPublic").prop('checked', false);
});
$("#btnSave").on("click", function(){
@@ -161,52 +161,52 @@ jQuery(function(){
$("#tblUser tbody tr").remove();
$.each(data || [], function(i, e){
var row = '' +
- '' + e.username + ' ' +
- '' + e.email + ' ';
- if(e.HasAdminRole == 1){
- row += '' + i18n.getMessage("button_on") + ' ';
+ '' + e.username + ' ' +
+ '' + e.email + ' ';
+ if(e.has_admin_role == 1){
+ row += '' + i18n.getMessage("button_on") + ' ';
} else {
- row += '' + i18n.getMessage("button_off") + ' ';
+ row += '' + i18n.getMessage("button_off") + ' ';
}
- row += ' ';
+ row += ' ';
row += ' ';
$("#tblUser tbody").append(row);
});
}
}).exec()
- ).done(function(){
- $("#tblUser tbody tr :button").on("click",function(){
- var userId = $(this).attr("userid");
- var self = this;
- new AjaxUtil({
- url: "/api/users/" + userId,
- type: "put",
- complete: function(jqXhr, status){
- if(jqXhr && jqXhr.status == 200){
- if($(self).hasClass("btn-success")){
- $(self).removeClass("btn-success").addClass("btn-danger");
- $(self).html(i18n.getMessage("button_off"));
- }else{
- $(self).removeClass("btn-danger").addClass("btn-success");
- $(self).html(i18n.getMessage("button_on"));
- }
- }
- }
- }).exec();
- });
- $("#tblUser tbody tr").on("mouseover", function(){
- $(".tdDeleteUser", this).css({"visibility":"visible"});
- }).on("mouseout", function(){
- $(".tdDeleteUser", this).css({"visibility":"hidden"});
- });
- $("#tblUser tbody tr .tdDeleteUser").on("click", function(){
- var userId = $(this).attr("userid");
- $("#dlgModal")
+ ).done(function(){
+ $("#tblUser tbody tr :button").on("click",function(){
+ var userId = $(this).attr("userid");
+ var self = this;
+ new AjaxUtil({
+ url: "/api/users/" + userId,
+ type: "put",
+ complete: function(jqXhr, status){
+ if(jqXhr && jqXhr.status == 200){
+ if($(self).hasClass("btn-success")){
+ $(self).removeClass("btn-success").addClass("btn-danger");
+ $(self).html(i18n.getMessage("button_off"));
+ }else{
+ $(self).removeClass("btn-danger").addClass("btn-success");
+ $(self).html(i18n.getMessage("button_on"));
+ }
+ }
+ }
+ }).exec();
+ });
+ $("#tblUser tbody tr").on("mouseover", function(e){
+ $(".tdDeleteUser", this).css({"visibility":"visible"});
+ }).on("mouseout", function(e){
+ $(".tdDeleteUser", this).css({"visibility":"hidden"});
+ });
+ $("#tblUser tbody tr .tdDeleteUser").on("click", function(e){
+ var userId = $(this).attr("userid");
+ $("#dlgModal")
.dialogModal({
"title": i18n.getMessage("delete_user"),
"content": i18n.getMessage("are_you_sure_to_delete_user") + $(this).attr("username") + " ?",
"enableCancel": true,
- "callback": function(){
+ "callback": function(){
new AjaxUtil({
url: "/api/users/" + userId,
type: "delete",
@@ -218,17 +218,18 @@ jQuery(function(){
error: function(jqXhr){}
}).exec();
}
+ });
+
});
});
+ }
+ listUserAdminRole(null);
+ $("#btnSearchUsername").on("click", function(){
+ var username = $("#txtSearchUsername").val();
+ if($.trim(username).length == 0){
+ username = null;
+ }
+ listUserAdminRole(username);
});
}
- listUserAdminRole(null);
- $("#btnSearchUsername").on("click", function(){
- var username = $("#txtSearchUsername").val();
- if($.trim(username).length == 0){
- username = null;
- }
- listUserAdminRole(username);
- });
- }
-})
+ })
diff --git a/static/resources/js/register.js b/static/resources/js/register.js
index 3fa2882b4..397087c01 100644
--- a/static/resources/js/register.js
+++ b/static/resources/js/register.js
@@ -30,14 +30,14 @@ jQuery(function(){
$("#btnPageSignUp").on("click", function(){
validateOptions.Validate(function() {
- var username = $.trim($("#Username").val());
- var email = $.trim($("#Email").val());
- var password = $.trim($("#Password").val());
- var confirmedPassword = $.trim($("#ConfirmedPassword").val());
- var realname = $.trim($("#Realname").val());
- var comment = $.trim($("#Comment").val());
- var isAdmin = $("#isAdmin").val();
-
+ var username = $.trim($("#Username").val());
+ var email = $.trim($("#Email").val());
+ var password = $.trim($("#Password").val());
+ var confirmedPassword = $.trim($("#ConfirmedPassword").val());
+ var realname = $.trim($("#Realname").val());
+ var comment = $.trim($("#Comment").val());
+ var isAdmin = $("#isAdmin").val();
+
new AjaxUtil({
url : "/api/users",
data: {"username": username, "password": password, "realname": realname, "comment": comment, "email": email},
@@ -47,29 +47,29 @@ jQuery(function(){
},
error:function(jqxhr, status, error){
$("#dlgModal")
- .dialogModal({
- "title": i18n.getMessage("title_sign_up"),
- "content": i18n.getMessage("internal_error"),
- "callback": function(){
- return;
- }
- });
+ .dialogModal({
+ "title": i18n.getMessage("title_sign_up"),
+ "content": i18n.getMessage("internal_error"),
+ "callback": function(){
+ return;
+ }
+ });
},
complete: function(xhr, status){
$("#btnPageSignUp").prop("disabled", false);
if(xhr && xhr.status == 201){
$("#dlgModal")
- .dialogModal({
- "title": isAdmin == "true" ? i18n.getMessage("title_add_user") : i18n.getMessage("title_sign_up"),
- "content": isAdmin == "true" ? i18n.getMessage("added_user_successfully") : i18n.getMessage("registered_successfully"),
- "callback": function(){
- if(isAdmin == "true") {
- document.location = "/registry/project";
- }else{
- document.location = "/signIn";
- }
+ .dialogModal({
+ "title": isAdmin == "true" ? i18n.getMessage("title_add_user") : i18n.getMessage("title_sign_up"),
+ "content": isAdmin == "true" ? i18n.getMessage("added_user_successfully") : i18n.getMessage("registered_successfully"),
+ "callback": function(){
+ if(isAdmin == "true") {
+ document.location = "/registry/project";
+ }else{
+ document.location = "/signIn";
}
- });
+ }
+ });
}
}
}).exec();
diff --git a/static/resources/js/reset-password.js b/static/resources/js/reset-password.js
index 0a3efc566..a6c504f48 100644
--- a/static/resources/js/reset-password.js
+++ b/static/resources/js/reset-password.js
@@ -17,11 +17,11 @@ jQuery(function(){
$("#Password,#ConfirmedPassword").on("blur", validateCallback);
validateOptions.Items = ["#Password", "#ConfirmedPassword"];
- function bindEnterKey(){
+ function bindEnterKey(){
$(document).on("keydown", function(e){
if(e.keyCode == 13){
- e.preventDefault();
- $("#btnSubmit").trigger("click");
+ e.preventDefault();
+ $("#btnSubmit").trigger("click");
}
});
}
@@ -30,7 +30,6 @@ jQuery(function(){
}
bindEnterKey();
-
var spinner = new Spinner({scale:1}).spin();
$("#btnSubmit").on("click", function(){
@@ -42,20 +41,20 @@ jQuery(function(){
"type": "post",
"data": {"reset_uuid": resetUuid, "password": password},
"beforeSend": function(e){
- unbindEnterKey();
- $("h1").append(spinner.el);
- $("#btnSubmit").prop("disabled", true);
+ unbindEnterKey();
+ $("h1").append(spinner.el);
+ $("#btnSubmit").prop("disabled", true);
},
"success": function(data, status, xhr){
if(xhr && xhr.status == 200){
$("#dlgModal")
- .dialogModal({
- "title": i18n.getMessage("title_reset_password"),
- "content": i18n.getMessage("reset_password_successfully"),
- "callback": function(){
- document.location="/signIn";
- }
- });
+ .dialogModal({
+ "title": i18n.getMessage("title_reset_password"),
+ "content": i18n.getMessage("reset_password_successfully"),
+ "callback": function(){
+ document.location="/signIn";
+ }
+ });
}
},
@@ -66,14 +65,14 @@ jQuery(function(){
"error": function(jqXhr, status, error){
if(jqXhr){
$("#dlgModal")
- .dialogModal({
- "title": i18n.getMessage("title_reset_password"),
- "content": i18n.getMessage(jqXhr.responseText),
- "callback": function(){
- bindEnterKey();
- return;
- }
- });
+ .dialogModal({
+ "title": i18n.getMessage("title_reset_password"),
+ "content": i18n.getMessage(jqXhr.responseText),
+ "callback": function(){
+ bindEnterKey();
+ return;
+ }
+ });
}
}
});
diff --git a/static/resources/js/search.js b/static/resources/js/search.js
index 5284866f9..e0158baa8 100644
--- a/static/resources/js/search.js
+++ b/static/resources/js/search.js
@@ -60,12 +60,12 @@ jQuery(function(){
$.each(data, function(i, e){
var project, description, repoName;
switch(discriminator){
- case "project":
+ case "project":
project = new Project(e.id, e.name, e.public);
description = project.name;
repoName = "";
break;
- case "repository":
+ case "repository":
project = new Project(e.project_id, e.project_name, e.project_public);
description = e.repository_name;
repoName = e.repository_name.substring(e.repository_name.lastIndexOf("/") + 1);
diff --git a/static/resources/js/sign-in.js b/static/resources/js/sign-in.js
index 1602a6b04..2aaa24c5f 100644
--- a/static/resources/js/sign-in.js
+++ b/static/resources/js/sign-in.js
@@ -56,7 +56,7 @@ jQuery(function(){
success: function(jqXhr, status){
var lastUri = location.search;
if(lastUri != "" && lastUri.indexOf("=") > 0){
- document.location = decodeURIComponent(lastUri.split("=")[1]);
+ document.location = decodeURIComponent(lastUri.split("=")[1]);
}else{
document.location = "/registry/project";
}
@@ -69,10 +69,10 @@ jQuery(function(){
i18nKey = "check_your_username_or_password"
}
$("#dlgModal")
- .dialogModal({
- "title": i18n.getMessage("title_login_failed"),
- "content": i18n.getMessage(i18nKey)
- });
+ .dialogModal({
+ "title": i18n.getMessage("title_login_failed"),
+ "content": i18n.getMessage(i18nKey)
+ });
}
});
});
diff --git a/static/resources/js/validate-options.js b/static/resources/js/validate-options.js
index 34f28ead9..492366ca7 100644
--- a/static/resources/js/validate-options.js
+++ b/static/resources/js/validate-options.js
@@ -26,18 +26,18 @@ var validateOptions = {
"Username" :{
"Required": { "value" : true, "errMsg" : i18n.getMessage("username_is_required")},
"CheckExist": { "value" : function(value){
- var result = true;
- $.ajax({
- url: "/userExists",
- data: {"target": "username", "value" : value},
+ var result = true;
+ $.ajax({
+ url: "/userExists",
+ data: {"target": "username", "value" : value},
dataType: "json",
- type: "post",
- async: false,
- success: function(data){
- result = data;
- }
- });
- return result;
+ type: "post",
+ async: false,
+ success: function(data){
+ result = data;
+ }
+ });
+ return result;
}, "errMsg" : i18n.getMessage("username_has_been_taken")},
"MaxLength": {"value" : 20, "errMsg" : i18n.getMessage("username_is_too_long")},
"IllegalChar": {"value": [",","~","#", "$", "%"] , "errMsg": i18n.getMessage("username_contains_illegal_chars")}
@@ -45,40 +45,40 @@ var validateOptions = {
"Email" :{
"Required": { "value" : true, "errMsg" : i18n.getMessage("email_is_required")},
"RegExp": {"value": /^(([^<>()[\]\\.,;:\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,}))$/,
- "errMsg": i18n.getMessage("email_contains_illegal_chars")},
+ "errMsg": i18n.getMessage("email_contains_illegal_chars")},
"CheckExist": { "value" : function(value){
- var result = true;
- $.ajax({
- url: "/userExists",
- data: {"target": "email", "value": value},
- dataType: "json",
- type: "post",
- async: false,
- success: function(data){
- result = data;
- }
- });
- return result;
- }, "errMsg" : i18n.getMessage("email_has_been_taken")}
+ var result = true;
+ $.ajax({
+ url: "/userExists",
+ data: {"target": "email", "value": value},
+ dataType: "json",
+ type: "post",
+ async: false,
+ success: function(data){
+ result = data;
+ }
+ });
+ return result;
+ }, "errMsg" : i18n.getMessage("email_has_been_taken")}
},
"EmailF" :{
"Required": { "value" : true, "errMsg" : i18n.getMessage("email_is_required")},
"RegExp": {"value": /^(([^<>()[\]\\.,;:\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,}))$/,
- "errMsg": i18n.getMessage("email_content_illegal")},
+ "errMsg": i18n.getMessage("email_content_illegal")},
"CheckIfNotExist": { "value" : function(value){
- var result = true;
- $.ajax({
- url: "/userExists",
- data: {"target": "email", "value": value},
- dataType: "json",
- type: "post",
- async: false,
- success: function(data){
- result = data;
- }
- });
- return result;
- }, "errMsg" : i18n.getMessage("email_does_not_exist")}
+ var result = true;
+ $.ajax({
+ url: "/userExists",
+ data: {"target": "email", "value": value},
+ dataType: "json",
+ type: "post",
+ async: false,
+ success: function(data){
+ result = data;
+ }
+ });
+ return result;
+ }, "errMsg" : i18n.getMessage("email_does_not_exist")}
},
"Realname" :{
"Required": { "value" : true, "errMsg" : i18n.getMessage("realname_is_required")},
@@ -119,7 +119,7 @@ function validateCallback(target){
var currentId = $(target).attr("id");
var validateItem = validateOptions[currentId];
- var errMsg = "";
+ var errMsg = "";
for(var checkTitle in validateItem){
diff --git a/tests/apitests/apilib/accesslog.go b/tests/apitests/apilib/accesslog.go
new file mode 100644
index 000000000..0d6318102
--- /dev/null
+++ b/tests/apitests/apilib/accesslog.go
@@ -0,0 +1,23 @@
+/*
+ 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 HarborAPI
+
+type AccessLog struct {
+ Username string `json:"username,omitempty"`
+ Keywords string `json:"keywords,omitempty"`
+ BeginTimestamp int32 `json:"beginTimestamp,omitempty"`
+ EndTimestamp int32 `json:"endTimestamp,omitempty"`
+}
diff --git a/tests/apitests/apilib/harborapi.go b/tests/apitests/apilib/harborapi.go
new file mode 100644
index 000000000..ee0d0d9e1
--- /dev/null
+++ b/tests/apitests/apilib/harborapi.go
@@ -0,0 +1,113 @@
+//Package HarborAPI
+//These APIs provide services for manipulating Harbor project.
+package HarborAPI
+
+import (
+ "encoding/json"
+ //"fmt"
+ "io/ioutil"
+ "net/http"
+
+ "github.com/dghubble/sling"
+)
+
+type HarborAPI struct {
+ basePath string
+}
+
+func NewHarborAPI() *HarborAPI {
+ return &HarborAPI{
+ basePath: "http://localhost",
+ }
+}
+
+func NewHarborAPIWithBasePath(basePath string) *HarborAPI {
+ return &HarborAPI{
+ basePath: basePath,
+ }
+}
+
+type UsrInfo struct {
+ Name string
+ Passwd string
+}
+
+//Search for projects and repositories
+//Implementation Notes
+//The Search endpoint returns information about the projects and repositories
+//offered at public status or related to the current logged in user.
+//The response includes the project and repository list in a proper display order.
+//@param q Search parameter for project and repository name.
+//@return []Search
+//func (a HarborAPI) SearchGet (q string) (Search, error) {
+func (a HarborAPI) SearchGet(q string) (Search, error) {
+
+ _sling := sling.New().Get(a.basePath)
+
+ // create path and map variables
+ path := "/api/search"
+
+ _sling = _sling.Path(path)
+
+ type QueryParams struct {
+ Query string `url:"q"`
+ }
+
+ _sling = _sling.QueryStruct(&QueryParams{q})
+
+ // accept header
+ accepts := []string{"application/json", "text/plain"}
+ for key := range accepts {
+ _sling = _sling.Set("Accept", accepts[key])
+ break // only use the first Accept
+ }
+
+ req, err := _sling.Request()
+ client := &http.Client{}
+ httpResponse, err := client.Do(req)
+ defer httpResponse.Body.Close()
+
+ body, err := ioutil.ReadAll(httpResponse.Body)
+ if err != nil {
+ // handle error
+ }
+
+ var successPayload = new(Search)
+ err = json.Unmarshal(body, &successPayload)
+ return *successPayload, err
+}
+
+//Create a new project.
+//Implementation Notes
+//This endpoint is for user to create a new project.
+//@param project New created project.
+//@return void
+//func (a HarborAPI) ProjectsPost (prjUsr UsrInfo, project Project) (int, error) {
+func (a HarborAPI) ProjectsPost(prjUsr UsrInfo, project Project) (int, error) {
+
+ _sling := sling.New().Post(a.basePath)
+
+ // create path and map variables
+ path := "/api/projects"
+
+ _sling = _sling.Path(path)
+
+ // accept header
+ accepts := []string{"application/json", "text/plain"}
+ for key := range accepts {
+ _sling = _sling.Set("Accept", accepts[key])
+ break // only use the first Accept
+ }
+
+ // body params
+ _sling = _sling.BodyJSON(project)
+
+ req, err := _sling.Request()
+ req.SetBasicAuth(prjUsr.Name, prjUsr.Passwd)
+
+ client := &http.Client{}
+ httpResponse, err := client.Do(req)
+ defer httpResponse.Body.Close()
+
+ return httpResponse.StatusCode, err
+}
diff --git a/tests/apitests/apilib/harborlogout.go b/tests/apitests/apilib/harborlogout.go
new file mode 100644
index 000000000..fa59ee2bb
--- /dev/null
+++ b/tests/apitests/apilib/harborlogout.go
@@ -0,0 +1,15 @@
+// HarborLogout.go
+package HarborAPI
+
+import (
+ "net/http"
+)
+
+func (a HarborAPI) HarborLogout() (int, error) {
+
+ response, err := http.Get(a.basePath + "/logout")
+
+ defer response.Body.Close()
+
+ return response.StatusCode, err
+}
diff --git a/tests/apitests/apilib/harlogin.go b/tests/apitests/apilib/harlogin.go
new file mode 100644
index 000000000..d711103bb
--- /dev/null
+++ b/tests/apitests/apilib/harlogin.go
@@ -0,0 +1,28 @@
+// HarborLogon.go
+package HarborAPI
+
+import (
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+func (a HarborAPI) HarborLogin(user UsrInfo) (int, error) {
+
+ v := url.Values{}
+ v.Set("principal", user.Name)
+ v.Set("password", user.Passwd)
+
+ body := ioutil.NopCloser(strings.NewReader(v.Encode())) //endode v:[body struce]
+
+ client := &http.Client{}
+ reqest, err := http.NewRequest("POST", a.basePath+"/login", body)
+
+ reqest.Header.Set("Content-Type", "application/x-www-form-urlencoded;param=value") //setting post head
+
+ resp, err := client.Do(reqest)
+ defer resp.Body.Close() //close resp.Body
+
+ return resp.StatusCode, err
+}
diff --git a/tests/apitests/apilib/project.go b/tests/apitests/apilib/project.go
new file mode 100644
index 000000000..19444957b
--- /dev/null
+++ b/tests/apitests/apilib/project.go
@@ -0,0 +1,15 @@
+package HarborAPI
+
+import ()
+
+type Project struct {
+ ProjectId int32 `json:"id,omitempty"`
+ OwnerId int32 `json:"owner_id,omitempty"`
+ ProjectName string `json:"project_name,omitempty"`
+ CreationTime string `json:"creation_time,omitempty"`
+ Deleted int32 `json:"deleted,omitempty"`
+ UserId int32 `json:"user_id,omitempty"`
+ OwnerName string `json:"owner_name,omitempty"`
+ Public bool `json:"public,omitempty"`
+ Togglable bool `json:"togglable,omitempty"`
+}
diff --git a/tests/apitests/apilib/projecttemp4search.go b/tests/apitests/apilib/projecttemp4search.go
new file mode 100644
index 000000000..c7219cc97
--- /dev/null
+++ b/tests/apitests/apilib/projecttemp4search.go
@@ -0,0 +1,9 @@
+package HarborAPI
+
+import ()
+
+type Project4Search struct {
+ ProjectId int32 `json:"id,omitempty"`
+ ProjectName string `json:"name,omitempty"`
+ Public int32 `json:"public,omitempty"`
+}
diff --git a/tests/apitests/apilib/repository.go b/tests/apitests/apilib/repository.go
new file mode 100644
index 000000000..5de9302df
--- /dev/null
+++ b/tests/apitests/apilib/repository.go
@@ -0,0 +1,16 @@
+package HarborAPI
+
+import (
+ "time"
+)
+
+type Repository struct {
+ Id string `json:"id,omitempty"`
+ Parent string `json:"parent,omitempty"`
+ Created time.Time `json:"created,omitempty"`
+ DurationDays string `json:"duration_days,omitempty"`
+ Author string `json:"author,omitempty"`
+ Architecture string `json:"architecture,omitempty"`
+ DockerVersion string `json:"docker_version,omitempty"`
+ Os string `json:"os,omitempty"`
+}
diff --git a/tests/apitests/apilib/repositorytemp4search.go b/tests/apitests/apilib/repositorytemp4search.go
new file mode 100644
index 000000000..f0dead98b
--- /dev/null
+++ b/tests/apitests/apilib/repositorytemp4search.go
@@ -0,0 +1,9 @@
+package HarborAPI
+
+type Repository4Search struct {
+ ProjectId int32 `json:"project_id,omitempty"`
+ ProjectName string `json:"project_name,omitempty"`
+ ProjectPublic int32 `json:"project_public,omitempty"`
+ RepoName string `json:"repository_name,omitempty"`
+}
+
diff --git a/tests/apitests/apilib/role.go b/tests/apitests/apilib/role.go
new file mode 100644
index 000000000..c6e53b044
--- /dev/null
+++ b/tests/apitests/apilib/role.go
@@ -0,0 +1,7 @@
+package HarborAPI
+
+type Role struct {
+ RoleId int32 `json:"role_id,omitempty"`
+ RoleCode string `json:"role_code,omitempty"`
+ RoleName string `json:"role_name,omitempty"`
+}
diff --git a/tests/apitests/apilib/roleparam.go b/tests/apitests/apilib/roleparam.go
new file mode 100644
index 000000000..12cf755a5
--- /dev/null
+++ b/tests/apitests/apilib/roleparam.go
@@ -0,0 +1,6 @@
+package HarborAPI
+
+type RoleParam struct {
+ Roles []int32 `json:"roles,omitempty"`
+ UserName string `json:"user_name,omitempty"`
+}
diff --git a/tests/apitests/apilib/search.go b/tests/apitests/apilib/search.go
new file mode 100644
index 000000000..81ca0fb20
--- /dev/null
+++ b/tests/apitests/apilib/search.go
@@ -0,0 +1,8 @@
+package HarborAPI
+
+import ()
+
+type Search struct {
+ Projects []Project4Search `json:"project,omitempty"`
+ Repositories []Repository4Search `json:"repository,omitempty"`
+}
diff --git a/tests/apitests/apilib/user.go b/tests/apitests/apilib/user.go
new file mode 100644
index 000000000..10a07933d
--- /dev/null
+++ b/tests/apitests/apilib/user.go
@@ -0,0 +1,11 @@
+package HarborAPI
+
+type User struct {
+ UserId int32 `json:"user_id,omitempty"`
+ Username string `json:"username,omitempty"`
+ Email string `json:"email,omitempty"`
+ Password string `json:"password,omitempty"`
+ Realname string `json:"realname,omitempty"`
+ Comment string `json:"comment,omitempty"`
+ Deleted int32 `json:"deleted,omitempty"`
+}
diff --git a/tests/apitests/hbapiaddprj_test.go b/tests/apitests/hbapiaddprj_test.go
new file mode 100644
index 000000000..4bb73ed8c
--- /dev/null
+++ b/tests/apitests/hbapiaddprj_test.go
@@ -0,0 +1,95 @@
+package HarborAPItest
+
+import (
+ "fmt"
+ "github.com/stretchr/testify/assert"
+ "testing"
+ "github.com/vmware/harbor/tests/apitests/apilib"
+)
+
+func TestAddProject(t *testing.T) {
+
+ fmt.Println("Test for Project Add (ProjectsPost) API\n")
+ assert := assert.New(t)
+
+ apiTest := HarborAPI.NewHarborAPI()
+
+ //prepare for test
+ adminEr := &HarborAPI.UsrInfo{"admin", "Harbor1234"}
+ admin := &HarborAPI.UsrInfo{"admin", "Harbor12345"}
+
+ prjUsr := &HarborAPI.UsrInfo{"unknown", "unknown"}
+
+ var project HarborAPI.Project
+ project.ProjectName = "testProject"
+ project.Public = true
+
+ //case 1: admin login fail, expect project creation fail.
+ fmt.Println("case 1: admin login fail, expect project creation fail.")
+ resault, err := apiTest.HarborLogin(*adminEr)
+ if err != nil {
+ t.Error("Error while admin login", err.Error())
+ t.Log(err)
+ } else {
+ assert.Equal(resault, int(401), "Admin login status should be 401")
+ //t.Log(resault)
+ }
+
+ resault, err = apiTest.ProjectsPost(*prjUsr, project)
+ if err != nil {
+ t.Error("Error while creat project", err.Error())
+ t.Log(err)
+ } else {
+ assert.Equal(resault, int(401), "Case 1: Project creation status should be 401")
+ //t.Log(resault)
+ }
+
+ //case 2: admin successful login, expect project creation success.
+ fmt.Println("case 2: admin successful login, expect project creation success.")
+ resault, err = apiTest.HarborLogin(*admin)
+ if err != nil {
+ t.Error("Error while admin login", err.Error())
+ t.Log(err)
+ } else {
+ assert.Equal(resault, int(200), "Admin login status should be 200")
+ //t.Log(resault)
+ }
+ if resault != 200 {
+ t.Log(resault)
+ } else {
+ prjUsr = admin
+ }
+
+ resault, err = apiTest.ProjectsPost(*prjUsr, project)
+ if err != nil {
+ t.Error("Error while creat project", err.Error())
+ t.Log(err)
+ } else {
+ assert.Equal(resault, int(201), "Case 2: Project creation status should be 201")
+ //t.Log(resault)
+ }
+
+ //case 3: duplicate project name, create project fail
+ fmt.Println("case 3: duplicate project name, create project fail")
+ resault, err = apiTest.ProjectsPost(*prjUsr, project)
+ if err != nil {
+ t.Error("Error while creat project", err.Error())
+ t.Log(err)
+ } else {
+ assert.Equal(resault, int(409), "Case 3: Project creation status should be 409")
+ //t.Log(resault)
+ }
+
+ //resault1, err := apiTest.HarborLogout()
+ //if err != nil {
+ // t.Error("Error while admin logout", err.Error())
+ // t.Log(err)
+ //} else {
+ // assert.Equal(resault1, int(200), "Admin logout status")
+ // //t.Log(resault)
+ //}
+ //if resault1 != 200 {
+ // t.Log(resault)
+ //}
+
+}
diff --git a/tests/apitests/hbapisearch_test.go b/tests/apitests/hbapisearch_test.go
new file mode 100644
index 000000000..1d449d408
--- /dev/null
+++ b/tests/apitests/hbapisearch_test.go
@@ -0,0 +1,31 @@
+package HarborAPItest
+
+import (
+ "fmt"
+ "github.com/stretchr/testify/assert"
+ "testing"
+ "github.com/vmware/harbor/tests/apitests/apilib"
+)
+
+func TestSearch(t *testing.T) {
+ fmt.Println("Test for Search (SearchGet) API\n")
+ assert := assert.New(t)
+
+ apiTest := HarborAPI.NewHarborAPI()
+ var resault HarborAPI.Search
+ resault, err := apiTest.SearchGet("library")
+ //fmt.Printf("%+v\n", resault)
+ if err != nil {
+ t.Error("Error while search project or repository", err.Error())
+ t.Log(err)
+ } else {
+ assert.Equal(resault.Projects[0].ProjectId, int32(1), "Project id should be equal")
+ assert.Equal(resault.Projects[0].ProjectName, "library", "Project name should be library")
+ assert.Equal(resault.Projects[0].Public, int32(1), "Project public status should be 1 (true)")
+ //t.Log(resault)
+ }
+ //if resault.Response.StatusCode != 200 {
+ // t.Log(resault.Response)
+ //}
+
+}
diff --git a/tests/hostcfg.sh b/tests/hostcfg.sh
new file mode 100755
index 000000000..d25c9dfec
--- /dev/null
+++ b/tests/hostcfg.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+IP=`ip addr s eth0 |grep "inet "|awk '{print $2}' |awk -F "/" '{print $1}'`
+#echo $IP
+sed "s/reg.mydomain.com/$IP/" -i Deploy/harbor.cfg
diff --git a/tests/startuptest.go b/tests/startuptest.go
new file mode 100644
index 000000000..f611ef58c
--- /dev/null
+++ b/tests/startuptest.go
@@ -0,0 +1,36 @@
+// Fetch prints the content found at a URL.
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "os"
+ "strings"
+ "time"
+)
+
+func main() {
+ time.Sleep(60*time.Second)
+ for _, url := range os.Args[1:] {
+ resp, err := http.Get(url)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "fetch: %v\n", err)
+ os.Exit(1)
+ }
+ b, err := ioutil.ReadAll(resp.Body)
+ resp.Body.Close()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "fetch: reading %s: %v\n", url, err)
+ os.Exit(1)
+ }
+// fmt.Printf("%s", b)
+ if strings.Contains(string(b), "Harbor") {
+ fmt.Printf("sucess!\n")
+ } else {
+ os.Exit(1)
+ }
+
+ }
+}
+
diff --git a/tests/testprepare.sh b/tests/testprepare.sh
new file mode 100755
index 000000000..0d9a30ce2
--- /dev/null
+++ b/tests/testprepare.sh
@@ -0,0 +1,11 @@
+IP=`ip addr s eth0 |grep "inet "|awk '{print $2}' |awk -F "/" '{print $1}'`
+#echo $IP
+docker pull hello-world
+docker pull docker
+#docker login -u admin -p Harbor12345 $IP
+
+docker tag hello-world $IP/library/hello-world
+docker push $IP/library/hello-world
+
+docker tag docker $IP/library/docker
+docker push $IP/library/docker
diff --git a/tests/userlogintest.go b/tests/userlogintest.go
new file mode 100644
index 000000000..3e8303119
--- /dev/null
+++ b/tests/userlogintest.go
@@ -0,0 +1,55 @@
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "strings"
+ "flag"
+)
+
+func main() {
+ usrNamePtr := flag.String("name","anaymous","user name")
+ usrPasswdPtr := flag.String("passwd","anaymous","user password")
+ flag.Parse()
+
+ v := url.Values{}
+ v.Set("principal", *usrNamePtr)
+ v.Set("password", *usrPasswdPtr)
+
+ body := ioutil.NopCloser(strings.NewReader(v.Encode())) //endode v:[body struce]
+ fmt.Println(v)
+
+ client := &http.Client{}
+ reqest, err := http.NewRequest("POST", "http://localhost/login", body)
+ if err != nil {
+ fmt.Println("Fatal error ", err.Error())
+ }
+
+ reqest.Header.Set("Content-Type", "application/x-www-form-urlencoded;param=value") //setting post head
+
+ resp, err := client.Do(reqest)
+ defer resp.Body.Close() //close resp.Body
+
+ fmt.Println("login status: ", resp.StatusCode) //print status code
+
+ //content_post, err := ioutil.ReadAll(resp.Body)
+ //if err != nil {
+ // fmt.Println("Fatal error ", err.Error())
+ //}
+
+ //fmt.Println(string(content_post)) //print reply
+
+ response, err := http.Get("http://localhost/api/logout")
+ if err != nil {
+ fmt.Println("Fatal error ", err.Error())
+ }
+
+ defer response.Body.Close()
+
+ fmt.Println("logout status: ", resp.StatusCode) //print status code
+ //content_get, err := ioutil.ReadAll(response.Body)
+ //fmt.Println(string(content_get))
+
+}
diff --git a/views/change-password.tpl b/views/change-password.tpl
index cdcbdb9a5..9dfa50494 100644
--- a/views/change-password.tpl
+++ b/views/change-password.tpl
@@ -16,32 +16,32 @@
diff --git a/views/forgot-password.tpl b/views/forgot-password.tpl
index 64f8656b7..0a2738479 100644
--- a/views/forgot-password.tpl
+++ b/views/forgot-password.tpl
@@ -19,19 +19,19 @@
{{i18n .Lang "title_forgot_password"}}
diff --git a/views/index.tpl b/views/index.tpl
index e92eaa5cb..dec019fb1 100644
--- a/views/index.tpl
+++ b/views/index.tpl
@@ -13,25 +13,25 @@
limitations under the License.
-->
-
-
-
-
{{i18n .Lang "index_title"}}
-
-
+
+
+
+
{{i18n .Lang "index_title"}}
+
+
-
-
-
-
-
{{i18n .Lang "index_desc"}}
-
{{i18n .Lang "index_desc_0"}}
-
{{i18n .Lang "index_desc_1"}}
-
{{i18n .Lang "index_desc_2"}}
-
{{i18n .Lang "index_desc_3"}}
-
{{i18n .Lang "index_desc_4"}}
-
{{i18n .Lang "index_desc_5"}}
-
-
-
+
+
+
+
+
{{i18n .Lang "index_desc"}}
+
{{i18n .Lang "index_desc_0"}}
+
{{i18n .Lang "index_desc_1"}}
+
{{i18n .Lang "index_desc_2"}}
+
{{i18n .Lang "index_desc_3"}}
+
{{i18n .Lang "index_desc_4"}}
+
{{i18n .Lang "index_desc_5"}}
+
+
+
\ No newline at end of file
diff --git a/views/item-detail.tpl b/views/item-detail.tpl
index e9cdb2753..cce2c2aa3 100644
--- a/views/item-detail.tpl
+++ b/views/item-detail.tpl
@@ -18,7 +18,7 @@
{{.ProjectName}}