mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-26 12:15:20 +01:00
Merge pull request #4611 from stonezdj/change_rest_api_pm
Change project member REST API
This commit is contained in:
commit
04335de72b
@ -448,186 +448,7 @@ paths:
|
|||||||
description: Project or metadata does not exist.
|
description: Project or metadata does not exist.
|
||||||
'500':
|
'500':
|
||||||
description: Internal server errors.
|
description: Internal server errors.
|
||||||
'/projects/{project_id}/members/':
|
'/projects/{project_id}/members':
|
||||||
get:
|
|
||||||
summary: Return a project's relevant role members.
|
|
||||||
description: >
|
|
||||||
This endpoint is for user to search a specified project's relevant role
|
|
||||||
members.
|
|
||||||
parameters:
|
|
||||||
- name: project_id
|
|
||||||
in: path
|
|
||||||
type: integer
|
|
||||||
format: int64
|
|
||||||
required: true
|
|
||||||
description: Relevant project ID.
|
|
||||||
tags:
|
|
||||||
- Products
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: Get project's relevant role members successfully.
|
|
||||||
schema:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: '#/definitions/User'
|
|
||||||
'400':
|
|
||||||
description: Illegal format of provided ID value.
|
|
||||||
'401':
|
|
||||||
description: User need to log in first.
|
|
||||||
'403':
|
|
||||||
description: User in session does not have permission to the project.
|
|
||||||
'404':
|
|
||||||
description: Project ID does not exist.
|
|
||||||
'500':
|
|
||||||
description: Unexpected internal errors.
|
|
||||||
post:
|
|
||||||
summary: Add project role member accompany with relevant project and user.
|
|
||||||
description: >
|
|
||||||
This endpoint is for user to add project role member accompany with
|
|
||||||
relevant project and user.
|
|
||||||
parameters:
|
|
||||||
- name: project_id
|
|
||||||
in: path
|
|
||||||
type: integer
|
|
||||||
format: int64
|
|
||||||
required: true
|
|
||||||
description: Relevant project ID.
|
|
||||||
- name: roles
|
|
||||||
in: body
|
|
||||||
description: >-
|
|
||||||
Role members for adding to relevant project. Only one role is
|
|
||||||
supported in the role list.
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/RoleParam'
|
|
||||||
tags:
|
|
||||||
- Products
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: Role members added to relevant project successfully.
|
|
||||||
'400':
|
|
||||||
description: Illegal format of provided ID value.
|
|
||||||
'401':
|
|
||||||
description: User need to log in first.
|
|
||||||
'403':
|
|
||||||
description: User in session does not have permission to the project.
|
|
||||||
'404':
|
|
||||||
description: Project ID or username does not exist.
|
|
||||||
'409':
|
|
||||||
description: User has already added as a project role member.
|
|
||||||
'415':
|
|
||||||
$ref: '#/responses/UnsupportedMediaType'
|
|
||||||
'500':
|
|
||||||
description: Unexpected internal errors.
|
|
||||||
'/projects/{project_id}/members/{user_id}':
|
|
||||||
get:
|
|
||||||
summary: Return role members accompany with relevant project and user.
|
|
||||||
description: >
|
|
||||||
This endpoint is for user to get role members accompany with relevant
|
|
||||||
project and user.
|
|
||||||
parameters:
|
|
||||||
- name: project_id
|
|
||||||
in: path
|
|
||||||
type: integer
|
|
||||||
format: int64
|
|
||||||
required: true
|
|
||||||
description: Relevant project ID
|
|
||||||
- name: user_id
|
|
||||||
in: path
|
|
||||||
type: integer
|
|
||||||
format: int
|
|
||||||
required: true
|
|
||||||
description: Relevant user ID
|
|
||||||
tags:
|
|
||||||
- Products
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: Get project role members successfully.
|
|
||||||
schema:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: '#/definitions/Role'
|
|
||||||
'400':
|
|
||||||
description: Illegal format of provided ID value.
|
|
||||||
'401':
|
|
||||||
description: User need to log in first.
|
|
||||||
'403':
|
|
||||||
description: User in session does not have permission to the project.
|
|
||||||
'404':
|
|
||||||
description: Project ID does not exist.
|
|
||||||
'500':
|
|
||||||
description: Unexpected internal errors.
|
|
||||||
put:
|
|
||||||
summary: Update project role members accompany with relevant project and user.
|
|
||||||
description: >
|
|
||||||
This endpoint is for user to update current project role members
|
|
||||||
accompany with relevant project and user.
|
|
||||||
parameters:
|
|
||||||
- name: project_id
|
|
||||||
in: path
|
|
||||||
type: integer
|
|
||||||
format: int64
|
|
||||||
required: true
|
|
||||||
description: Relevant project ID.
|
|
||||||
- name: user_id
|
|
||||||
in: path
|
|
||||||
type: integer
|
|
||||||
format: int
|
|
||||||
required: true
|
|
||||||
description: Relevant user ID.
|
|
||||||
- name: roles
|
|
||||||
in: body
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/RoleParam'
|
|
||||||
description: Updates for roles and username.
|
|
||||||
tags:
|
|
||||||
- Products
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: Project role members updated successfully.
|
|
||||||
'400':
|
|
||||||
description: Illegal format of provided ID value.
|
|
||||||
'401':
|
|
||||||
description: User need to log in first.
|
|
||||||
'403':
|
|
||||||
description: User in session does not have permission to the project.
|
|
||||||
'404':
|
|
||||||
description: Project ID does not exist.
|
|
||||||
'500':
|
|
||||||
description: Unexpected internal errors.
|
|
||||||
delete:
|
|
||||||
summary: Delete project role members accompany with relevant project and user.
|
|
||||||
description: >
|
|
||||||
This endpoint is aimed to remove project role members already added to
|
|
||||||
the relevant project and user.
|
|
||||||
parameters:
|
|
||||||
- name: project_id
|
|
||||||
in: path
|
|
||||||
type: integer
|
|
||||||
format: int64
|
|
||||||
required: true
|
|
||||||
description: Relevant project ID.
|
|
||||||
- name: user_id
|
|
||||||
in: path
|
|
||||||
type: integer
|
|
||||||
format: int
|
|
||||||
required: true
|
|
||||||
description: Relevant user ID.
|
|
||||||
tags:
|
|
||||||
- Products
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: Project role members deleted successfully.
|
|
||||||
'400':
|
|
||||||
description: Illegal format of provided ID value.
|
|
||||||
'401':
|
|
||||||
description: User need to log in first.
|
|
||||||
'403':
|
|
||||||
description: User in session does not have permission to the project.
|
|
||||||
'404':
|
|
||||||
description: Project ID does not exist.
|
|
||||||
'500':
|
|
||||||
description: Unexpected internal errors.
|
|
||||||
'/projects/{project_id}/projectmembers':
|
|
||||||
get:
|
get:
|
||||||
summary: Get all project member information
|
summary: Get all project member information
|
||||||
description: Get all project member information
|
description: Get all project member information
|
||||||
@ -691,7 +512,7 @@ paths:
|
|||||||
description: Project does not exist.
|
description: Project does not exist.
|
||||||
'500':
|
'500':
|
||||||
description: Unexpected internal errors.
|
description: Unexpected internal errors.
|
||||||
'/projects/{project_id}/projectmembers/{mid}':
|
'/projects/{project_id}/members/{mid}':
|
||||||
get:
|
get:
|
||||||
summary: Get the project member information
|
summary: Get the project member information
|
||||||
description: Get the project member information
|
description: Get the project member information
|
||||||
@ -2492,6 +2313,71 @@ paths:
|
|||||||
$ref: '#/definitions/UserGroup'
|
$ref: '#/definitions/UserGroup'
|
||||||
'500':
|
'500':
|
||||||
description: Unexpected internal errors.
|
description: Unexpected internal errors.
|
||||||
|
/ldap/users/search:
|
||||||
|
get:
|
||||||
|
summary: Search available ldap users.
|
||||||
|
description: >
|
||||||
|
This endpoint searches the available ldap users based on related
|
||||||
|
configuration parameters. Support searched by input ladp configuration,
|
||||||
|
load configuration from the system and specific filter.
|
||||||
|
parameters:
|
||||||
|
- name: username
|
||||||
|
in: query
|
||||||
|
type: string
|
||||||
|
required: false
|
||||||
|
description: Registered user ID
|
||||||
|
tags:
|
||||||
|
- Products
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Search ldap users successfully.
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/LdapUsers'
|
||||||
|
'401':
|
||||||
|
description: User need to login first.
|
||||||
|
'403':
|
||||||
|
description: Only admin has this authority.
|
||||||
|
'500':
|
||||||
|
description: Unexpected internal errors.
|
||||||
|
/ldap/users/import:
|
||||||
|
post:
|
||||||
|
summary: Import selected available ldap users.
|
||||||
|
description: >
|
||||||
|
This endpoint adds the selected available ldap users to harbor based on
|
||||||
|
related configuration parameters from the system. System will try to
|
||||||
|
guess the user email address and realname, add to harbor user
|
||||||
|
information.
|
||||||
|
|
||||||
|
If have errors when import user, will return the list of importing
|
||||||
|
failed uid and the failed reason.
|
||||||
|
parameters:
|
||||||
|
- name: uid_list
|
||||||
|
in: body
|
||||||
|
description: >-
|
||||||
|
The uid listed for importing. This list will check users validity of
|
||||||
|
ldap service based on configuration from the system.
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/LdapImportUsers'
|
||||||
|
tags:
|
||||||
|
- Products
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Add ldap users successfully.
|
||||||
|
'401':
|
||||||
|
description: User need to login first.
|
||||||
|
'403':
|
||||||
|
description: Only admin has this authority.
|
||||||
|
'415':
|
||||||
|
$ref: '#/responses/UnsupportedMediaType'
|
||||||
|
'404':
|
||||||
|
description: Failed import some users.
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/LdapFailedImportUsers'
|
||||||
/usergroups:
|
/usergroups:
|
||||||
get:
|
get:
|
||||||
summary: Get all user groups information
|
summary: Get all user groups information
|
||||||
@ -2613,71 +2499,7 @@ paths:
|
|||||||
description: Only admin has this authority.
|
description: Only admin has this authority.
|
||||||
'500':
|
'500':
|
||||||
description: Unexpected internal errors.
|
description: Unexpected internal errors.
|
||||||
/ldap/users/search:
|
|
||||||
get:
|
|
||||||
summary: Search available ldap users.
|
|
||||||
description: >
|
|
||||||
This endpoint searches the available ldap users based on related
|
|
||||||
configuration parameters. Support searched by input ladp configuration,
|
|
||||||
load configuration from the system and specific filter.
|
|
||||||
parameters:
|
|
||||||
- name: username
|
|
||||||
in: query
|
|
||||||
type: string
|
|
||||||
required: false
|
|
||||||
description: Registered user ID
|
|
||||||
tags:
|
|
||||||
- Products
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: Search ldap users successfully.
|
|
||||||
schema:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: '#/definitions/LdapUsers'
|
|
||||||
'401':
|
|
||||||
description: User need to login first.
|
|
||||||
'403':
|
|
||||||
description: Only admin has this authority.
|
|
||||||
'500':
|
|
||||||
description: Unexpected internal errors.
|
|
||||||
/ldap/users/import:
|
|
||||||
post:
|
|
||||||
summary: Import selected available ldap users.
|
|
||||||
description: >
|
|
||||||
This endpoint adds the selected available ldap users to harbor based on
|
|
||||||
related configuration parameters from the system. System will try to
|
|
||||||
guess the user email address and realname, add to harbor user
|
|
||||||
information.
|
|
||||||
|
|
||||||
If have errors when import user, will return the list of importing
|
|
||||||
failed uid and the failed reason.
|
|
||||||
parameters:
|
|
||||||
- name: uid_list
|
|
||||||
in: body
|
|
||||||
description: >-
|
|
||||||
The uid listed for importing. This list will check users validity of
|
|
||||||
ldap service based on configuration from the system.
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/LdapImportUsers'
|
|
||||||
tags:
|
|
||||||
- Products
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: Add ldap users successfully.
|
|
||||||
'401':
|
|
||||||
description: User need to login first.
|
|
||||||
'403':
|
|
||||||
description: Only admin has this authority.
|
|
||||||
'415':
|
|
||||||
$ref: '#/responses/UnsupportedMediaType'
|
|
||||||
'404':
|
|
||||||
description: Failed import some users.
|
|
||||||
schema:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: '#/definitions/LdapFailedImportUsers'
|
|
||||||
/configurations:
|
/configurations:
|
||||||
get:
|
get:
|
||||||
summary: Get system configurations.
|
summary: Get system configurations.
|
||||||
@ -3799,4 +3621,3 @@ definitions:
|
|||||||
description: The DN of the LDAP group if group type is 1 (LDAP group).
|
description: The DN of the LDAP group if group type is 1 (LDAP group).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -635,31 +635,6 @@ func TestGetProjectById(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetUserByProject(t *testing.T) {
|
|
||||||
pid := currentProject.ProjectID
|
|
||||||
u1 := models.User{
|
|
||||||
Username: "Tester",
|
|
||||||
}
|
|
||||||
u2 := models.User{
|
|
||||||
Username: "nononono",
|
|
||||||
}
|
|
||||||
users, err := GetUserByProject(pid, u1)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error happened in GetUserByProject: %v, project Id: %d, user: %+v", err, pid, u1)
|
|
||||||
}
|
|
||||||
if len(users) != 1 {
|
|
||||||
t.Errorf("unexpected length of user list, expected: 1, the users list: %+v", users)
|
|
||||||
}
|
|
||||||
users, err = GetUserByProject(pid, u2)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error happened in GetUserByProject: %v, project Id: %d, user: %+v", err, pid, u2)
|
|
||||||
}
|
|
||||||
if len(users) != 0 {
|
|
||||||
t.Errorf("unexpected length of user list, expected: 0, the users list: %+v", users)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetUserProjectRoles(t *testing.T) {
|
func TestGetUserProjectRoles(t *testing.T) {
|
||||||
r, err := GetUserProjectRoles(currentUser.UserID, currentProject.ProjectID, common.UserMember)
|
r, err := GetUserProjectRoles(currentUser.UserID, currentProject.ProjectID, common.UserMember)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -700,68 +675,6 @@ func TestGetProjects(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddProjectMember(t *testing.T) {
|
|
||||||
pmid, err := AddProjectMember(currentProject.ProjectID, 1, models.DEVELOPER, common.UserMember)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error occurred in AddProjectMember: %v", err)
|
|
||||||
}
|
|
||||||
if pmid == 0 {
|
|
||||||
t.Errorf("Error add project member, pmid=0")
|
|
||||||
}
|
|
||||||
pmid, err = AddProjectMember(currentProject.ProjectID, 1, models.DEVELOPER, "randomstring")
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Should failed on adding project member when adding duplicated items")
|
|
||||||
}
|
|
||||||
|
|
||||||
roles, err := GetUserProjectRoles(1, currentProject.ProjectID, common.UserMember)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error occurred in GetUserProjectRoles: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
flag := false
|
|
||||||
for _, role := range roles {
|
|
||||||
if role.Name == "developer" {
|
|
||||||
flag = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !flag {
|
|
||||||
t.Errorf("the user which ID is 1 does not have developer privileges")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpdateProjectMember(t *testing.T) {
|
|
||||||
err := UpdateProjectMember(currentProject.ProjectID, 1, models.GUEST, "randomstring")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error occurred in UpdateProjectMember: %v", err)
|
|
||||||
}
|
|
||||||
roles, err := GetUserProjectRoles(1, currentProject.ProjectID, common.UserMember)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error occurred in GetUserProjectRoles: %v", err)
|
|
||||||
}
|
|
||||||
if roles[0].Name != "guest" {
|
|
||||||
t.Errorf("The user with ID 1 is not guest role after update, the acutal role: %s", roles[0].Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeleteProjectMember(t *testing.T) {
|
|
||||||
err := DeleteProjectMember(currentProject.ProjectID, 1, "randomstring")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error occurred in DeleteProjectMember: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
roles, err := GetUserProjectRoles(1, currentProject.ProjectID, common.UserMember)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error occurred in GetUserProjectRoles: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(roles) != 0 {
|
|
||||||
t.Errorf("delete record failed from table project_member")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetRoleByID(t *testing.T) {
|
func TestGetRoleByID(t *testing.T) {
|
||||||
r, err := GetRoleByID(models.PROJECTADMIN)
|
r, err := GetRoleByID(models.PROJECTADMIN)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -17,14 +17,12 @@ package dao
|
|||||||
import (
|
import (
|
||||||
"github.com/vmware/harbor/src/common"
|
"github.com/vmware/harbor/src/common"
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
|
"github.com/vmware/harbor/src/common/utils/log"
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
//"github.com/vmware/harbor/src/common/utils/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//TODO:transaction, return err
|
|
||||||
|
|
||||||
// AddProject adds a project to the database along with project roles information and access log records.
|
// AddProject adds a project to the database along with project roles information and access log records.
|
||||||
func AddProject(project models.Project) (int64, error) {
|
func AddProject(project models.Project) (int64, error) {
|
||||||
|
|
||||||
@ -45,13 +43,47 @@ func AddProject(project models.Project) (int64, error) {
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pmID, err := AddProjectMember(projectID, project.OwnerID, models.PROJECTADMIN, common.UserMember)
|
pmID, err := addProjectMember(models.Member{
|
||||||
|
ProjectID: projectID,
|
||||||
|
EntityID: project.OwnerID,
|
||||||
|
Role: models.PROJECTADMIN,
|
||||||
|
EntityType: common.UserMember,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
if pmID == 0 {
|
if pmID == 0 {
|
||||||
return projectID, fmt.Errorf("Failed to add project member, pmid=0")
|
return projectID, fmt.Errorf("Failed to add project member, pmid=0")
|
||||||
}
|
}
|
||||||
return projectID, err
|
return projectID, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addProjectMember(member models.Member) (int, error) {
|
||||||
|
|
||||||
|
log.Debugf("Adding project member %+v", member)
|
||||||
|
|
||||||
|
o := GetOrmer()
|
||||||
|
|
||||||
|
if member.EntityID <= 0 {
|
||||||
|
return 0, fmt.Errorf("Invalid entity_id, member: %+v", member)
|
||||||
|
}
|
||||||
|
|
||||||
|
if member.ProjectID <= 0 {
|
||||||
|
return 0, fmt.Errorf("Invalid project_id, member: %+v", member)
|
||||||
|
}
|
||||||
|
|
||||||
|
sql := "insert into project_member (project_id, entity_id , role, entity_type) values (?, ?, ?, ?)"
|
||||||
|
r, err := o.Raw(sql, member.ProjectID, member.EntityID, member.Role, member.EntityType).Exec()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
pmid, err := r.LastInsertId()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int(pmid), err
|
||||||
|
}
|
||||||
|
|
||||||
// GetProjectByID ...
|
// GetProjectByID ...
|
||||||
func GetProjectByID(id int64) (*models.Project, error) {
|
func GetProjectByID(id int64) (*models.Project, error) {
|
||||||
o := GetOrmer()
|
o := GetOrmer()
|
||||||
|
@ -74,7 +74,6 @@ func GetProjectMember(queryMember models.Member) ([]*models.Member, error) {
|
|||||||
func AddProjectMember(member models.Member) (int, error) {
|
func AddProjectMember(member models.Member) (int, error) {
|
||||||
|
|
||||||
log.Debugf("Adding project member %+v", member)
|
log.Debugf("Adding project member %+v", member)
|
||||||
|
|
||||||
o := dao.GetOrmer()
|
o := dao.GetOrmer()
|
||||||
|
|
||||||
if member.EntityID <= 0 {
|
if member.EntityID <= 0 {
|
||||||
@ -85,6 +84,11 @@ func AddProjectMember(member models.Member) (int, error) {
|
|||||||
return 0, fmt.Errorf("Invalid project_id, member: %+v", member)
|
return 0, fmt.Errorf("Invalid project_id, member: %+v", member)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delSQL := "delete from project_member where project_id = ? and entity_id = ? and entity_type = ? "
|
||||||
|
_, err := o.Raw(delSQL, member.ProjectID, member.EntityID, member.EntityType).Exec()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
sql := "insert into project_member (project_id, entity_id , role, entity_type) values (?, ?, ?, ?)"
|
sql := "insert into project_member (project_id, entity_id , role, entity_type) values (?, ?, ?, ?)"
|
||||||
r, err := o.Raw(sql, member.ProjectID, member.EntityID, member.Role, member.EntityType).Exec()
|
r, err := o.Raw(sql, member.ProjectID, member.EntityID, member.Role, member.EntityType).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -99,7 +103,6 @@ func AddProjectMember(member models.Member) (int, error) {
|
|||||||
|
|
||||||
// UpdateProjectMemberRole updates the record in table project_member, only role can be changed
|
// UpdateProjectMemberRole updates the record in table project_member, only role can be changed
|
||||||
func UpdateProjectMemberRole(pmID int, role int) error {
|
func UpdateProjectMemberRole(pmID int, role int) error {
|
||||||
|
|
||||||
o := dao.GetOrmer()
|
o := dao.GetOrmer()
|
||||||
sql := "update project_member set role = ? where id = ? "
|
sql := "update project_member set role = ? where id = ? "
|
||||||
_, err := o.Raw(sql, role, pmID).Exec()
|
_, err := o.Raw(sql, role, pmID).Exec()
|
||||||
|
@ -1,95 +0,0 @@
|
|||||||
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package dao
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/vmware/harbor/src/common"
|
|
||||||
"github.com/vmware/harbor/src/common/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddProjectMember inserts a record to table project_member
|
|
||||||
func AddProjectMember(projectID int64, userID int, role int, entityType string) (int, error) {
|
|
||||||
o := GetOrmer()
|
|
||||||
if !(entityType == common.UserMember || entityType == common.GroupMember) {
|
|
||||||
entityType = common.UserMember
|
|
||||||
}
|
|
||||||
sql := `insert into project_member (project_id, entity_id , role, entity_type) values (?, ?, ?, ?)`
|
|
||||||
_, err := o.Raw(sql, projectID, userID, role, entityType).Exec()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
var pmid int
|
|
||||||
querySQL := `select id from project_member where project_id = ? and entity_id = ? and entity_type = ? limit 1`
|
|
||||||
|
|
||||||
err = o.Raw(querySQL, projectID, userID, entityType).QueryRow(&pmid)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return pmid, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateProjectMember updates the record in table project_member
|
|
||||||
func UpdateProjectMember(projectID int64, userID int, role int, entityType string) error {
|
|
||||||
o := GetOrmer()
|
|
||||||
if !(entityType == common.UserMember || entityType == common.GroupMember) {
|
|
||||||
entityType = common.UserMember
|
|
||||||
}
|
|
||||||
|
|
||||||
sql := `update project_member set role = ? where project_id = ? and entity_id = ?`
|
|
||||||
|
|
||||||
_, err := o.Raw(sql, role, projectID, userID).Exec()
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteProjectMember delete the record from table project_member
|
|
||||||
func DeleteProjectMember(projectID int64, userID int, entityType string) error {
|
|
||||||
o := GetOrmer()
|
|
||||||
|
|
||||||
if !(entityType == common.UserMember || entityType == common.GroupMember) {
|
|
||||||
entityType = common.UserMember
|
|
||||||
}
|
|
||||||
|
|
||||||
sql := `delete from project_member where project_id = ? and entity_id = ? and entity_type = ?`
|
|
||||||
|
|
||||||
if _, err := o.Raw(sql, projectID, userID, entityType).Exec(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUserByProject gets all members of the project.
|
|
||||||
func GetUserByProject(projectID int64, queryUser models.User) ([]*models.UserMember, error) {
|
|
||||||
o := GetOrmer()
|
|
||||||
sql := `select pm.id as id, u.user_id, u.username, u.creation_time, u.update_time, r.name as rolename,
|
|
||||||
r.role_id as role, pm.entity_type as entity_type from user u join project_member pm
|
|
||||||
on pm.project_id = ? and u.user_id = pm.entity_id
|
|
||||||
join role r on pm.role = r.role_id where u.deleted = 0 and pm.entity_type = 'u' `
|
|
||||||
|
|
||||||
queryParam := make([]interface{}, 1)
|
|
||||||
queryParam = append(queryParam, projectID)
|
|
||||||
|
|
||||||
if len(queryUser.Username) != 0 {
|
|
||||||
sql += ` and u.username like ? `
|
|
||||||
queryParam = append(queryParam, `%`+Escape(queryUser.Username)+`%`)
|
|
||||||
}
|
|
||||||
sql += ` order by u.username `
|
|
||||||
|
|
||||||
members := []*models.UserMember{}
|
|
||||||
_, err := o.Raw(sql, queryParam).QueryRows(&members)
|
|
||||||
|
|
||||||
return members, err
|
|
||||||
}
|
|
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/vmware/harbor/src/common"
|
"github.com/vmware/harbor/src/common"
|
||||||
"github.com/vmware/harbor/src/common/dao"
|
"github.com/vmware/harbor/src/common/dao"
|
||||||
|
"github.com/vmware/harbor/src/common/dao/project"
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
"github.com/vmware/harbor/src/common/utils/log"
|
"github.com/vmware/harbor/src/common/utils/log"
|
||||||
"github.com/vmware/harbor/src/ui/promgr"
|
"github.com/vmware/harbor/src/ui/promgr"
|
||||||
@ -122,25 +123,39 @@ func TestMain(m *testing.M) {
|
|||||||
private.ProjectID = id
|
private.ProjectID = id
|
||||||
defer dao.DeleteProject(id)
|
defer dao.DeleteProject(id)
|
||||||
|
|
||||||
|
var projectAdminPMID, developerUserPMID, guestUserPMID int
|
||||||
// add project members
|
// add project members
|
||||||
_, err = dao.AddProjectMember(private.ProjectID, projectAdminUser.UserID, common.RoleProjectAdmin, common.UserMember)
|
projectAdminPMID, err = project.AddProjectMember(models.Member{
|
||||||
|
ProjectID: private.ProjectID,
|
||||||
|
EntityID: projectAdminUser.UserID,
|
||||||
|
EntityType: common.UserMember,
|
||||||
|
Role: common.RoleProjectAdmin,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to add member: %v", err)
|
log.Fatalf("failed to add member: %v", err)
|
||||||
}
|
}
|
||||||
defer dao.DeleteProjectMember(private.ProjectID, projectAdminUser.UserID, common.UserMember)
|
defer project.DeleteProjectMemberByID(projectAdminPMID)
|
||||||
|
|
||||||
_, err = dao.AddProjectMember(private.ProjectID, developerUser.UserID, common.RoleDeveloper, common.UserMember)
|
developerUserPMID, err = project.AddProjectMember(models.Member{
|
||||||
|
ProjectID: private.ProjectID,
|
||||||
|
EntityID: developerUser.UserID,
|
||||||
|
EntityType: common.UserMember,
|
||||||
|
Role: common.RoleDeveloper,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to add member: %v", err)
|
log.Fatalf("failed to add member: %v", err)
|
||||||
}
|
}
|
||||||
defer dao.DeleteProjectMember(private.ProjectID, developerUser.UserID, common.UserMember)
|
defer project.DeleteProjectMemberByID(developerUserPMID)
|
||||||
|
guestUserPMID, err = project.AddProjectMember(models.Member{
|
||||||
_, err = dao.AddProjectMember(private.ProjectID, guestUser.UserID, common.RoleGuest, common.UserMember)
|
ProjectID: private.ProjectID,
|
||||||
|
EntityID: guestUser.UserID,
|
||||||
|
EntityType: common.UserMember,
|
||||||
|
Role: common.RoleGuest,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to add member: %v", err)
|
log.Fatalf("failed to add member: %v", err)
|
||||||
}
|
}
|
||||||
defer dao.DeleteProjectMember(private.ProjectID, guestUser.UserID, common.UserMember)
|
defer project.DeleteProjectMemberByID(guestUserPMID)
|
||||||
|
|
||||||
os.Exit(m.Run())
|
os.Exit(m.Run())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,13 +31,14 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/vmware/harbor/src/common/dao"
|
"github.com/vmware/harbor/src/common/dao"
|
||||||
|
"github.com/vmware/harbor/src/common/dao/project"
|
||||||
common_http "github.com/vmware/harbor/src/common/http"
|
common_http "github.com/vmware/harbor/src/common/http"
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
nonSysAdminID, projAdminID, projDeveloperID, projGuestID int
|
nonSysAdminID, projAdminID, projDeveloperID, projGuestID int64
|
||||||
|
projAdminPMID, projDeveloperPMID, projGuestPMID int
|
||||||
// The following users/credentials are registered and assigned roles at the beginning of
|
// The following users/credentials are registered and assigned roles at the beginning of
|
||||||
// running testing and cleaned up at the end.
|
// running testing and cleaned up at the end.
|
||||||
// Do not try to change the system and project roles that the users have during
|
// Do not try to change the system and project roles that the users have during
|
||||||
@ -206,7 +207,8 @@ func TestMain(m *testing.M) {
|
|||||||
|
|
||||||
func prepare() error {
|
func prepare() error {
|
||||||
// register nonSysAdmin
|
// register nonSysAdmin
|
||||||
id, err := dao.Register(models.User{
|
var err error
|
||||||
|
nonSysAdminID, err = dao.Register(models.User{
|
||||||
Username: nonSysAdmin.Name,
|
Username: nonSysAdmin.Name,
|
||||||
Password: nonSysAdmin.Passwd,
|
Password: nonSysAdmin.Passwd,
|
||||||
Email: nonSysAdmin.Name + "@test.com",
|
Email: nonSysAdmin.Name + "@test.com",
|
||||||
@ -214,10 +216,9 @@ func prepare() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
nonSysAdminID = int(id)
|
|
||||||
|
|
||||||
// register projAdmin and assign project admin role
|
// register projAdmin and assign project admin role
|
||||||
id, err = dao.Register(models.User{
|
projAdminID, err = dao.Register(models.User{
|
||||||
Username: projAdmin.Name,
|
Username: projAdmin.Name,
|
||||||
Password: projAdmin.Passwd,
|
Password: projAdmin.Passwd,
|
||||||
Email: projAdmin.Name + "@test.com",
|
Email: projAdmin.Name + "@test.com",
|
||||||
@ -225,14 +226,18 @@ func prepare() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
projAdminID = int(id)
|
|
||||||
|
|
||||||
if _, err = dao.AddProjectMember(1, projAdminID, models.PROJECTADMIN, common.UserMember); err != nil {
|
if projAdminPMID, err = project.AddProjectMember(models.Member{
|
||||||
|
ProjectID: 1,
|
||||||
|
Role: models.PROJECTADMIN,
|
||||||
|
EntityID: int(projAdminID),
|
||||||
|
EntityType: common.UserMember,
|
||||||
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// register projDeveloper and assign project developer role
|
// register projDeveloper and assign project developer role
|
||||||
id, err = dao.Register(models.User{
|
projDeveloperID, err = dao.Register(models.User{
|
||||||
Username: projDeveloper.Name,
|
Username: projDeveloper.Name,
|
||||||
Password: projDeveloper.Passwd,
|
Password: projDeveloper.Passwd,
|
||||||
Email: projDeveloper.Name + "@test.com",
|
Email: projDeveloper.Name + "@test.com",
|
||||||
@ -240,14 +245,18 @@ func prepare() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
projDeveloperID = int(id)
|
|
||||||
|
|
||||||
if _, err = dao.AddProjectMember(1, projDeveloperID, models.DEVELOPER, common.UserMember); err != nil {
|
if projDeveloperPMID, err = project.AddProjectMember(models.Member{
|
||||||
|
ProjectID: 1,
|
||||||
|
Role: models.DEVELOPER,
|
||||||
|
EntityID: int(projDeveloperID),
|
||||||
|
EntityType: common.UserMember,
|
||||||
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// register projGuest and assign project guest role
|
// register projGuest and assign project guest role
|
||||||
id, err = dao.Register(models.User{
|
projGuestID, err = dao.Register(models.User{
|
||||||
Username: projGuest.Name,
|
Username: projGuest.Name,
|
||||||
Password: projGuest.Passwd,
|
Password: projGuest.Passwd,
|
||||||
Email: projGuest.Name + "@test.com",
|
Email: projGuest.Name + "@test.com",
|
||||||
@ -255,23 +264,29 @@ func prepare() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
projGuestID = int(id)
|
|
||||||
|
|
||||||
_, err = dao.AddProjectMember(1, projGuestID, models.GUEST, common.UserMember)
|
if projGuestPMID, err = project.AddProjectMember(models.Member{
|
||||||
|
ProjectID: 1,
|
||||||
|
Role: models.GUEST,
|
||||||
|
EntityID: int(projGuestID),
|
||||||
|
EntityType: common.UserMember,
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func clean() {
|
func clean() {
|
||||||
ids := []int{projAdminID, projDeveloperID, projGuestID}
|
pmids := []int{projAdminPMID, projDeveloperPMID, projGuestPMID}
|
||||||
for _, id := range ids {
|
|
||||||
if err := dao.DeleteProjectMember(1, id, common.UserMember); err != nil {
|
for _, id := range pmids {
|
||||||
|
if err := project.DeleteProjectMemberByID(id); err != nil {
|
||||||
fmt.Printf("failed to clean up member %d from project library: %v", id, err)
|
fmt.Printf("failed to clean up member %d from project library: %v", id, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
userids := []int64{nonSysAdminID, projAdminID, projDeveloperID, projGuestID}
|
||||||
ids = append(ids, nonSysAdminID)
|
for _, id := range userids {
|
||||||
for _, id := range ids {
|
if err := dao.DeleteUser(int(id)); err != nil {
|
||||||
if err := dao.DeleteUser(id); err != nil {
|
|
||||||
fmt.Printf("failed to clean up user %d: %v \n", id, err)
|
fmt.Printf("failed to clean up user %d: %v \n", id, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,11 +104,10 @@ func init() {
|
|||||||
beego.Router("/api/users/:id/sysadmin", &UserAPI{}, "put:ToggleUserAdminRole")
|
beego.Router("/api/users/:id/sysadmin", &UserAPI{}, "put:ToggleUserAdminRole")
|
||||||
beego.Router("/api/projects/:id([0-9]+)/logs", &ProjectAPI{}, "get:Logs")
|
beego.Router("/api/projects/:id([0-9]+)/logs", &ProjectAPI{}, "get:Logs")
|
||||||
beego.Router("/api/projects/:id([0-9]+)/_deletable", &ProjectAPI{}, "get:Deletable")
|
beego.Router("/api/projects/:id([0-9]+)/_deletable", &ProjectAPI{}, "get:Deletable")
|
||||||
beego.Router("/api/projects/:pid([0-9]+)/members/?:mid", &ProjectUserMemberAPI{}, "get:Get;post:Post;delete:Delete;put:Put")
|
|
||||||
beego.Router("/api/projects/:id([0-9]+)/metadatas/?:name", &MetadataAPI{}, "get:Get")
|
beego.Router("/api/projects/:id([0-9]+)/metadatas/?:name", &MetadataAPI{}, "get:Get")
|
||||||
beego.Router("/api/projects/:id([0-9]+)/metadatas/", &MetadataAPI{}, "post:Post")
|
beego.Router("/api/projects/:id([0-9]+)/metadatas/", &MetadataAPI{}, "post:Post")
|
||||||
beego.Router("/api/projects/:id([0-9]+)/metadatas/:name", &MetadataAPI{}, "put:Put;delete:Delete")
|
beego.Router("/api/projects/:id([0-9]+)/metadatas/:name", &MetadataAPI{}, "put:Put;delete:Delete")
|
||||||
beego.Router("/api/projects/:pid([0-9]+)/projectmembers/?:pmid([0-9]+)", &ProjectMemberAPI{})
|
beego.Router("/api/projects/:pid([0-9]+)/members/?:pmid([0-9]+)", &ProjectMemberAPI{})
|
||||||
beego.Router("/api/repositories", &RepositoryAPI{})
|
beego.Router("/api/repositories", &RepositoryAPI{})
|
||||||
beego.Router("/api/statistics", &StatisticAPI{})
|
beego.Router("/api/statistics", &StatisticAPI{})
|
||||||
beego.Router("/api/users/?:id", &UserAPI{})
|
beego.Router("/api/users/?:id", &UserAPI{})
|
||||||
@ -440,12 +439,13 @@ func (a testapi) GetProjectMembersByProID(prjUsr usrInfo, projectID string) (int
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Add project role member accompany with projectID
|
//Add project role member accompany with projectID
|
||||||
func (a testapi) AddProjectMember(prjUsr usrInfo, projectID string, roles apilib.RoleParam) (int, error) {
|
//func (a testapi) AddProjectMember(prjUsr usrInfo, projectID string, roles apilib.RoleParam) (int, error) {
|
||||||
|
func (a testapi) AddProjectMember(prjUsr usrInfo, projectID string, member *models.MemberReq) (int, error) {
|
||||||
_sling := sling.New().Post(a.basePath)
|
_sling := sling.New().Post(a.basePath)
|
||||||
|
|
||||||
path := "/api/projects/" + projectID + "/members/"
|
path := "/api/projects/" + projectID + "/members/"
|
||||||
_sling = _sling.Path(path)
|
_sling = _sling.Path(path)
|
||||||
_sling = _sling.BodyJSON(roles)
|
_sling = _sling.BodyJSON(member)
|
||||||
httpStatusCode, _, err := request(_sling, jsonAcceptHeader, prjUsr)
|
httpStatusCode, _, err := request(_sling, jsonAcceptHeader, prjUsr)
|
||||||
return httpStatusCode, err
|
return httpStatusCode, err
|
||||||
|
|
||||||
|
@ -1,271 +0,0 @@
|
|||||||
// Copyright (c) 2017 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 (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/vmware/harbor/src/common"
|
|
||||||
|
|
||||||
"github.com/vmware/harbor/src/common/dao"
|
|
||||||
"github.com/vmware/harbor/src/common/models"
|
|
||||||
"github.com/vmware/harbor/src/common/utils/log"
|
|
||||||
"github.com/vmware/harbor/src/ui/auth"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ProjectUserMemberAPI handles request to /api/projects/{}/members/{}
|
|
||||||
type ProjectUserMemberAPI struct {
|
|
||||||
BaseController
|
|
||||||
memberID int
|
|
||||||
currentUserID int
|
|
||||||
project *models.Project
|
|
||||||
}
|
|
||||||
|
|
||||||
type memberReq struct {
|
|
||||||
Username string `json:"username"`
|
|
||||||
UserID int `json:"user_id"`
|
|
||||||
Roles []int `json:"roles"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare validates the URL and parms
|
|
||||||
func (pma *ProjectUserMemberAPI) Prepare() {
|
|
||||||
pma.BaseController.Prepare()
|
|
||||||
|
|
||||||
if !pma.SecurityCtx.IsAuthenticated() {
|
|
||||||
pma.HandleUnauthorized()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
user, err := dao.GetUser(models.User{
|
|
||||||
Username: pma.SecurityCtx.GetUsername(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
pma.HandleInternalServerError(
|
|
||||||
fmt.Sprintf("failed to get user %s: %v",
|
|
||||||
pma.SecurityCtx.GetUsername(), err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pma.currentUserID = user.UserID
|
|
||||||
|
|
||||||
pid, err := pma.GetInt64FromPath(":pid")
|
|
||||||
if err != nil || pid <= 0 {
|
|
||||||
text := "invalid project ID: "
|
|
||||||
if err != nil {
|
|
||||||
text += err.Error()
|
|
||||||
} else {
|
|
||||||
text += fmt.Sprintf("%d", pid)
|
|
||||||
}
|
|
||||||
pma.HandleBadRequest(text)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
project, err := pma.ProjectMgr.Get(pid)
|
|
||||||
if err != nil {
|
|
||||||
pma.ParseAndHandleError(fmt.Sprintf("failed to get project %d", pid), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if project == nil {
|
|
||||||
pma.HandleNotFound(fmt.Sprintf("project %d not found", pid))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pma.project = project
|
|
||||||
|
|
||||||
if !(pma.Ctx.Input.IsGet() && pma.SecurityCtx.HasReadPerm(pid) ||
|
|
||||||
pma.SecurityCtx.HasAllPerm(pid)) {
|
|
||||||
pma.HandleForbidden(pma.SecurityCtx.GetUsername())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(pma.GetStringFromPath(":mid")) != 0 {
|
|
||||||
mid, err := pma.GetInt64FromPath(":mid")
|
|
||||||
if err != nil || mid <= 0 {
|
|
||||||
text := "invalid member ID: "
|
|
||||||
if err != nil {
|
|
||||||
text += err.Error()
|
|
||||||
} else {
|
|
||||||
text += fmt.Sprintf("%d", mid)
|
|
||||||
}
|
|
||||||
pma.HandleBadRequest(text)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
member, err := dao.GetUser(models.User{
|
|
||||||
UserID: int(mid),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
pma.HandleInternalServerError(fmt.Sprintf("failed to get user %d: %v", mid, err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if member == nil {
|
|
||||||
pma.HandleNotFound(fmt.Sprintf("member %d not found", mid))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pma.memberID = member.UserID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get ...
|
|
||||||
func (pma *ProjectUserMemberAPI) Get() {
|
|
||||||
pid := pma.project.ProjectID
|
|
||||||
if pma.memberID == 0 { //member id not set return list of the members
|
|
||||||
username := pma.GetString("username")
|
|
||||||
queryUser := models.User{Username: username}
|
|
||||||
userList, err := dao.GetUserByProject(pid, queryUser)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to query database for member list, error: %v", err)
|
|
||||||
pma.RenderError(http.StatusInternalServerError, "Internal Server Error")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pma.Data["json"] = userList
|
|
||||||
} else { //return detail of a member
|
|
||||||
roleList, err := listRoles(pma.memberID, pid, common.UserMember)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error occurred in GetUserProjectRoles, error: %v", err)
|
|
||||||
pma.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(roleList) == 0 {
|
|
||||||
pma.CustomAbort(http.StatusNotFound, fmt.Sprintf("user %d is not a member of the project", pma.memberID))
|
|
||||||
}
|
|
||||||
|
|
||||||
//return empty role list to indicate if a user is not a member
|
|
||||||
result := make(map[string]interface{})
|
|
||||||
user, err := dao.GetUser(models.User{UserID: pma.memberID})
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error occurred in GetUser, error: %v", err)
|
|
||||||
pma.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
|
||||||
}
|
|
||||||
result["username"] = user.Username
|
|
||||||
result["user_id"] = pma.memberID
|
|
||||||
result["roles"] = roleList
|
|
||||||
pma.Data["json"] = result
|
|
||||||
}
|
|
||||||
pma.ServeJSON()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Post ...
|
|
||||||
func (pma *ProjectUserMemberAPI) Post() {
|
|
||||||
projectID := pma.project.ProjectID
|
|
||||||
|
|
||||||
var req memberReq
|
|
||||||
pma.DecodeJSONReq(&req)
|
|
||||||
username := strings.TrimSpace(req.Username)
|
|
||||||
userID := checkUserExists(username)
|
|
||||||
if userID <= 0 {
|
|
||||||
|
|
||||||
user, err := auth.SearchUser(username)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed the search user, error: %v", err)
|
|
||||||
pma.RenderError(http.StatusInternalServerError, "Failed to search user")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if user == nil {
|
|
||||||
log.Errorf("Current user doesn't exist: %v", username)
|
|
||||||
pma.RenderError(http.StatusNotFound, "Failed to search user: "+username)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = auth.OnBoardUser(user)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed the onboard user, error: %s", err)
|
|
||||||
pma.RenderError(http.StatusInternalServerError, "Failed to onboard user")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if user.UserID <= 0 {
|
|
||||||
log.Error("Failed the onboard user, UserId <=0")
|
|
||||||
pma.RenderError(http.StatusInternalServerError, "Failed to onboard user")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
userID = user.UserID
|
|
||||||
|
|
||||||
}
|
|
||||||
rolelist, err := dao.GetUserProjectRoles(userID, projectID, common.UserMember)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error occurred in GetUserProjectRoles, error: %v", err)
|
|
||||||
pma.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
|
||||||
}
|
|
||||||
if len(rolelist) > 0 {
|
|
||||||
log.Warningf("user is already added to project, user id: %d, project id: %d", userID, projectID)
|
|
||||||
pma.RenderError(http.StatusConflict, "user is ready in project")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(req.Roles) <= 0 || len(req.Roles) > 1 {
|
|
||||||
pma.CustomAbort(http.StatusBadRequest, "only one role is supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
rid := req.Roles[0]
|
|
||||||
if !(rid == models.PROJECTADMIN ||
|
|
||||||
rid == models.DEVELOPER ||
|
|
||||||
rid == models.GUEST) {
|
|
||||||
pma.CustomAbort(http.StatusBadRequest, "invalid role")
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = dao.AddProjectMember(projectID, userID, rid, common.UserMember)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to update DB to add project user role, project id: %d, user id: %d, role id: %d", projectID, userID, rid)
|
|
||||||
pma.RenderError(http.StatusInternalServerError, "Failed to update data in database")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put ...
|
|
||||||
func (pma *ProjectUserMemberAPI) Put() {
|
|
||||||
pid := pma.project.ProjectID
|
|
||||||
mid := pma.memberID
|
|
||||||
|
|
||||||
var req memberReq
|
|
||||||
pma.DecodeJSONReq(&req)
|
|
||||||
roleList, err := dao.GetUserProjectRoles(mid, pid, common.UserMember)
|
|
||||||
if len(roleList) == 0 {
|
|
||||||
log.Warningf("User is not in project, user id: %d, project id: %d", mid, pid)
|
|
||||||
pma.RenderError(http.StatusNotFound, "user not exist in project")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//TODO: delete and insert should in one transaction
|
|
||||||
//delete user project role record for the given user
|
|
||||||
err = dao.DeleteProjectMember(pid, mid, common.UserMember)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to delete project roles for user, user id: %d, project id: %d, error: %v", mid, pid, err)
|
|
||||||
pma.RenderError(http.StatusInternalServerError, "Failed to update data in DB")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//insert roles in request
|
|
||||||
for _, rid := range req.Roles {
|
|
||||||
_, err = dao.AddProjectMember(pid, mid, int(rid), common.UserMember)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to update DB to add project user role, project id: %d, user id: %d, role id: %d", pid, mid, rid)
|
|
||||||
pma.RenderError(http.StatusInternalServerError, "Failed to update data in database")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete ...
|
|
||||||
func (pma *ProjectUserMemberAPI) Delete() {
|
|
||||||
pid := pma.project.ProjectID
|
|
||||||
mid := pma.memberID
|
|
||||||
|
|
||||||
err := dao.DeleteProjectMember(pid, mid, common.UserMember)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to delete project roles for user, user id: %d, project id: %d, error: %v", mid, pid, err)
|
|
||||||
pma.RenderError(http.StatusInternalServerError, "Failed to update data in DB")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,213 +0,0 @@
|
|||||||
// Copyright (c) 2017 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 (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/vmware/harbor/tests/apitests/apilib"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMemGet(t *testing.T) {
|
|
||||||
var result []apilib.User
|
|
||||||
var httpStatusCode int
|
|
||||||
var err error
|
|
||||||
|
|
||||||
assert := assert.New(t)
|
|
||||||
apiTest := newHarborAPI()
|
|
||||||
projectID := "1"
|
|
||||||
|
|
||||||
fmt.Println("Testing Member Get API")
|
|
||||||
//-------------------case 1 : response code = 200------------------------//
|
|
||||||
httpStatusCode, result, err = apiTest.GetProjectMembersByProID(*admin, projectID)
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Error whihle get members by projectID", err.Error())
|
|
||||||
t.Log(err)
|
|
||||||
} else {
|
|
||||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
|
||||||
assert.Equal("proj_admin", result[0].Username, "User name should be proj_admin")
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------case 2: Response Code=401,User need to log in first.----------//
|
|
||||||
fmt.Println("case 2: Response Code=401,User need to log in first.")
|
|
||||||
httpStatusCode, result, err = apiTest.GetProjectMembersByProID(*unknownUsr, projectID)
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Error while get members by projectID", err.Error())
|
|
||||||
t.Log(err)
|
|
||||||
} else {
|
|
||||||
assert.Equal(int(401), httpStatusCode, "Case 2: Project creation status should be 401")
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------case 3: Response Code=404,Project does not exist-----------//
|
|
||||||
fmt.Println("case 3: Response Code=404,Project does not exist")
|
|
||||||
projectID = "11"
|
|
||||||
httpStatusCode, result, err = apiTest.GetProjectMembersByProID(*admin, projectID)
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Error while get members by projectID", err.Error())
|
|
||||||
t.Log(err)
|
|
||||||
} else {
|
|
||||||
assert.Equal(int(404), httpStatusCode, "Case 3: Project creation status should be 404")
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------case 4: Response Code=404, member does not exist-----------//
|
|
||||||
fmt.Println("case 4: Response Code=404, member does not exist")
|
|
||||||
projectID = "1"
|
|
||||||
memberID := "10000"
|
|
||||||
httpStatusCode, err = apiTest.GetMemByPIDUID(*admin, projectID, memberID)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to get member %s of project %s: %v", memberID, projectID, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(int(404), httpStatusCode,
|
|
||||||
fmt.Sprintf("response status code should be 404 other than %d", httpStatusCode))
|
|
||||||
|
|
||||||
fmt.Printf("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add project role member accompany with projectID
|
|
||||||
* role_id = 1 : ProjectAdmin
|
|
||||||
* role_id = 2 : Developer
|
|
||||||
* role_id = 3 : Guest
|
|
||||||
*/
|
|
||||||
|
|
||||||
func TestMemPost(t *testing.T) {
|
|
||||||
var httpStatusCode int
|
|
||||||
var err error
|
|
||||||
|
|
||||||
assert := assert.New(t)
|
|
||||||
apiTest := newHarborAPI()
|
|
||||||
projectID := "1"
|
|
||||||
CommonAddUser()
|
|
||||||
roles := &apilib.RoleParam{[]int32{1}, TestUserName}
|
|
||||||
fmt.Printf("Add User \"%s\" successfully!\n", TestUserName)
|
|
||||||
|
|
||||||
fmt.Println("Testing Member Post API")
|
|
||||||
//-------------------case 1 : response code = 200------------------------//
|
|
||||||
fmt.Println("case 1: response code = 200")
|
|
||||||
httpStatusCode, err = apiTest.AddProjectMember(*admin, projectID, *roles)
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Error whihle add project role member", err.Error())
|
|
||||||
t.Log(err)
|
|
||||||
} else {
|
|
||||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------case 2: Response Code=409,User is ready in project.----------//
|
|
||||||
fmt.Println("case 2: Response Code=409,User is ready in project.")
|
|
||||||
httpStatusCode, err = apiTest.AddProjectMember(*admin, projectID, *roles)
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Error while add project role member", err.Error())
|
|
||||||
t.Log(err)
|
|
||||||
} else {
|
|
||||||
assert.Equal(int(409), httpStatusCode, "Case 2: httpStatusCode should be 409")
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------case 3: Response Code=404,User does not exist.----------//
|
|
||||||
fmt.Println("case 3: Response Code=404,User does not exist.")
|
|
||||||
|
|
||||||
errorRoles := &apilib.RoleParam{[]int32{1}, "T"}
|
|
||||||
httpStatusCode, err = apiTest.AddProjectMember(*admin, projectID, *errorRoles)
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Error while add project role member", err.Error())
|
|
||||||
t.Log(err)
|
|
||||||
} else {
|
|
||||||
assert.Equal(int(404), httpStatusCode, "Case 3: httpStatusCode status should be 404")
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
//---------case 4: Response Code=403,User in session does not have permission to the project..----------//
|
|
||||||
fmt.Println("case 4:User in session does not have permission to the project.")
|
|
||||||
|
|
||||||
httpStatusCode, err = apiTest.AddProjectMember(*testUser, projectID, *roles)
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Error while add project role member", err.Error())
|
|
||||||
t.Log(err)
|
|
||||||
} else {
|
|
||||||
assert.Equal(int(403), httpStatusCode, "Case 3: httpStatusCode status should be 403")
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetMemByPIDUID(t *testing.T) {
|
|
||||||
var httpStatusCode int
|
|
||||||
var err error
|
|
||||||
|
|
||||||
assert := assert.New(t)
|
|
||||||
apiTest := newHarborAPI()
|
|
||||||
projectID := "1"
|
|
||||||
userID := strconv.Itoa(CommonGetUserID())
|
|
||||||
fmt.Println("Testing Member Get API by PID and UID")
|
|
||||||
//-------------------case 1 : response code = 200------------------------//
|
|
||||||
fmt.Println("case 1: response code = 200")
|
|
||||||
httpStatusCode, err = apiTest.GetMemByPIDUID(*admin, projectID, userID)
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Error whihle get project role member", err.Error())
|
|
||||||
t.Log(err)
|
|
||||||
} else {
|
|
||||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPutMem(t *testing.T) {
|
|
||||||
var httpStatusCode int
|
|
||||||
var err error
|
|
||||||
|
|
||||||
assert := assert.New(t)
|
|
||||||
apiTest := newHarborAPI()
|
|
||||||
projectID := "1"
|
|
||||||
userID := strconv.Itoa(CommonGetUserID())
|
|
||||||
|
|
||||||
roles := &apilib.RoleParam{[]int32{3}, TestUserName}
|
|
||||||
fmt.Println("Testing Member Put API")
|
|
||||||
//-------------------case 1 : response code = 200------------------------//
|
|
||||||
fmt.Println("case 1: response code = 200")
|
|
||||||
httpStatusCode, err = apiTest.PutProjectMember(*admin, projectID, userID, *roles)
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Error whihle put project role member", err.Error())
|
|
||||||
t.Log(err)
|
|
||||||
} else {
|
|
||||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeleteMemUser(t *testing.T) {
|
|
||||||
var httpStatusCode int
|
|
||||||
var err error
|
|
||||||
|
|
||||||
assert := assert.New(t)
|
|
||||||
apiTest := newHarborAPI()
|
|
||||||
projectID := "1"
|
|
||||||
|
|
||||||
fmt.Println("Testing Member Delete API")
|
|
||||||
//-------------------case 1 : response code = 200------------------------//
|
|
||||||
fmt.Println("case 1: response code = 200")
|
|
||||||
|
|
||||||
id := strconv.Itoa(CommonGetUserID())
|
|
||||||
|
|
||||||
httpStatusCode, err = apiTest.DeleteProjectMember(*admin, projectID, id)
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Error whihle add project role member", err.Error())
|
|
||||||
t.Log(err)
|
|
||||||
} else {
|
|
||||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
|
||||||
}
|
|
||||||
CommonDelUser()
|
|
||||||
}
|
|
@ -136,14 +136,19 @@ func TestListProjects(t *testing.T) {
|
|||||||
|
|
||||||
//-------------------case 4 : add project member and check his role ------------------------//
|
//-------------------case 4 : add project member and check his role ------------------------//
|
||||||
CommonAddUser()
|
CommonAddUser()
|
||||||
roles := &apilib.RoleParam{[]int32{2}, TestUserName}
|
member := &models.MemberReq{
|
||||||
|
Role: 2,
|
||||||
|
MemberUser: models.User{
|
||||||
|
Username: TestUserName,
|
||||||
|
},
|
||||||
|
}
|
||||||
projectID := strconv.Itoa(addPID)
|
projectID := strconv.Itoa(addPID)
|
||||||
httpStatusCode, err = apiTest.AddProjectMember(*admin, projectID, *roles)
|
httpStatusCode, err = apiTest.AddProjectMember(*admin, projectID, member)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("Error whihle add project role member", err.Error())
|
t.Error("Error whihle add project role member", err.Error())
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
} else {
|
} else {
|
||||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
assert.Equal(int(201), httpStatusCode, "httpStatusCode should be 201")
|
||||||
}
|
}
|
||||||
httpStatusCode, result, err = apiTest.ProjectsGet(
|
httpStatusCode, result, err = apiTest.ProjectsGet(
|
||||||
&apilib.ProjectQuery{
|
&apilib.ProjectQuery{
|
||||||
|
@ -30,7 +30,7 @@ func TestProjectMemberAPI_Get(t *testing.T) {
|
|||||||
&codeCheckingCase{
|
&codeCheckingCase{
|
||||||
request: &testingRequest{
|
request: &testingRequest{
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
url: "/api/projects/1/projectmembers",
|
url: "/api/projects/1/members",
|
||||||
},
|
},
|
||||||
code: http.StatusUnauthorized,
|
code: http.StatusUnauthorized,
|
||||||
},
|
},
|
||||||
@ -38,7 +38,7 @@ func TestProjectMemberAPI_Get(t *testing.T) {
|
|||||||
&codeCheckingCase{
|
&codeCheckingCase{
|
||||||
request: &testingRequest{
|
request: &testingRequest{
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
url: "/api/projects/1/projectmembers",
|
url: "/api/projects/1/members",
|
||||||
credential: admin,
|
credential: admin,
|
||||||
},
|
},
|
||||||
code: http.StatusOK,
|
code: http.StatusOK,
|
||||||
@ -47,7 +47,7 @@ func TestProjectMemberAPI_Get(t *testing.T) {
|
|||||||
&codeCheckingCase{
|
&codeCheckingCase{
|
||||||
request: &testingRequest{
|
request: &testingRequest{
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
url: "/api/projects/0/projectmembers",
|
url: "/api/projects/0/members",
|
||||||
credential: admin,
|
credential: admin,
|
||||||
},
|
},
|
||||||
code: http.StatusBadRequest,
|
code: http.StatusBadRequest,
|
||||||
@ -56,7 +56,7 @@ func TestProjectMemberAPI_Get(t *testing.T) {
|
|||||||
&codeCheckingCase{
|
&codeCheckingCase{
|
||||||
request: &testingRequest{
|
request: &testingRequest{
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
url: "/api/projects/1/projectmembers/121",
|
url: "/api/projects/1/members/121",
|
||||||
credential: admin,
|
credential: admin,
|
||||||
},
|
},
|
||||||
code: http.StatusNotFound,
|
code: http.StatusNotFound,
|
||||||
@ -81,7 +81,7 @@ func TestProjectMemberAPI_Post(t *testing.T) {
|
|||||||
&codeCheckingCase{
|
&codeCheckingCase{
|
||||||
request: &testingRequest{
|
request: &testingRequest{
|
||||||
method: http.MethodPost,
|
method: http.MethodPost,
|
||||||
url: "/api/projects/1/projectmembers",
|
url: "/api/projects/1/members",
|
||||||
bodyJSON: &models.MemberReq{
|
bodyJSON: &models.MemberReq{
|
||||||
Role: 1,
|
Role: 1,
|
||||||
MemberUser: models.User{
|
MemberUser: models.User{
|
||||||
@ -94,7 +94,7 @@ func TestProjectMemberAPI_Post(t *testing.T) {
|
|||||||
&codeCheckingCase{
|
&codeCheckingCase{
|
||||||
request: &testingRequest{
|
request: &testingRequest{
|
||||||
method: http.MethodPost,
|
method: http.MethodPost,
|
||||||
url: "/api/projects/1/projectmembers",
|
url: "/api/projects/1/members",
|
||||||
bodyJSON: &models.MemberReq{
|
bodyJSON: &models.MemberReq{
|
||||||
Role: 1,
|
Role: 1,
|
||||||
MemberUser: models.User{
|
MemberUser: models.User{
|
||||||
@ -108,7 +108,7 @@ func TestProjectMemberAPI_Post(t *testing.T) {
|
|||||||
&codeCheckingCase{
|
&codeCheckingCase{
|
||||||
request: &testingRequest{
|
request: &testingRequest{
|
||||||
method: http.MethodPost,
|
method: http.MethodPost,
|
||||||
url: "/api/projects/1/projectmembers",
|
url: "/api/projects/1/members",
|
||||||
bodyJSON: &models.MemberReq{
|
bodyJSON: &models.MemberReq{
|
||||||
Role: 1,
|
Role: 1,
|
||||||
MemberUser: models.User{
|
MemberUser: models.User{
|
||||||
@ -144,8 +144,8 @@ func TestProjectMemberAPI_PutAndDelete(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error occurred when add project member: %v", err)
|
t.Errorf("Error occurred when add project member: %v", err)
|
||||||
}
|
}
|
||||||
URL := fmt.Sprintf("/api/projects/1/projectmembers/%v", ID)
|
URL := fmt.Sprintf("/api/projects/1/members/%v", ID)
|
||||||
badURL := fmt.Sprintf("/api/projects/1/projectmembers/%v", 0)
|
badURL := fmt.Sprintf("/api/projects/1/members/%v", 0)
|
||||||
cases := []*codeCheckingCase{
|
cases := []*codeCheckingCase{
|
||||||
// 401
|
// 401
|
||||||
&codeCheckingCase{
|
&codeCheckingCase{
|
||||||
|
@ -19,6 +19,8 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/vmware/harbor/src/common/dao/project"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/vmware/harbor/src/common"
|
"github.com/vmware/harbor/src/common"
|
||||||
@ -314,17 +316,21 @@ func TestRepPolicyAPIList(t *testing.T) {
|
|||||||
Password: "ProjectDev",
|
Password: "ProjectDev",
|
||||||
Email: "project_dev@test.com",
|
Email: "project_dev@test.com",
|
||||||
}
|
}
|
||||||
|
var proAdminPMID, proDevPMID int
|
||||||
proAdminID, err := dao.Register(projectAdmin)
|
proAdminID, err := dao.Register(projectAdmin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
defer dao.DeleteUser(int(proAdminID))
|
defer dao.DeleteUser(int(proAdminID))
|
||||||
|
if proAdminPMID, err = project.AddProjectMember(models.Member{
|
||||||
if _, err = dao.AddProjectMember(1, int(proAdminID), models.PROJECTADMIN, common.UserMember); err != nil {
|
ProjectID: 1,
|
||||||
|
Role: models.PROJECTADMIN,
|
||||||
|
EntityID: int(proAdminID),
|
||||||
|
EntityType: common.UserMember,
|
||||||
|
}); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
defer dao.DeleteProjectMember(1, int(proAdminID), common.UserMember)
|
defer project.DeleteProjectMemberByID(proAdminPMID)
|
||||||
|
|
||||||
proDevID, err := dao.Register(projectDev)
|
proDevID, err := dao.Register(projectDev)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -332,10 +338,15 @@ func TestRepPolicyAPIList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer dao.DeleteUser(int(proDevID))
|
defer dao.DeleteUser(int(proDevID))
|
||||||
|
|
||||||
if _, err = dao.AddProjectMember(1, int(proDevID), models.DEVELOPER, common.UserMember); err != nil {
|
if proDevPMID, err = project.AddProjectMember(models.Member{
|
||||||
|
ProjectID: 1,
|
||||||
|
Role: models.DEVELOPER,
|
||||||
|
EntityID: int(proDevID),
|
||||||
|
EntityType: common.UserMember,
|
||||||
|
}); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
defer dao.DeleteProjectMember(1, int(proDevID), common.UserMember)
|
defer project.DeleteProjectMemberByID(proDevPMID)
|
||||||
|
|
||||||
// 400: invalid project ID
|
// 400: invalid project ID
|
||||||
runCodeCheckingCases(t, &codeCheckingCase{
|
runCodeCheckingCases(t, &codeCheckingCase{
|
||||||
|
@ -20,6 +20,9 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/vmware/harbor/src/common/dao"
|
||||||
|
"github.com/vmware/harbor/src/common/dao/project"
|
||||||
|
"github.com/vmware/harbor/src/common/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetRepos(t *testing.T) {
|
func TestGetRepos(t *testing.T) {
|
||||||
@ -226,6 +229,24 @@ func TestPopulateAuthor(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPutOfRepository(t *testing.T) {
|
func TestPutOfRepository(t *testing.T) {
|
||||||
|
u, err := dao.GetUser(models.User{
|
||||||
|
Username: projAdmin.Name,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error occurred when Register user: %v", err)
|
||||||
|
}
|
||||||
|
pmid, err := project.AddProjectMember(
|
||||||
|
models.Member{
|
||||||
|
ProjectID: 1,
|
||||||
|
Role: 1,
|
||||||
|
EntityID: int(u.UserID),
|
||||||
|
EntityType: "u"},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error occurred when add project member: %v", err)
|
||||||
|
}
|
||||||
|
defer project.DeleteProjectMemberByID(pmid)
|
||||||
|
|
||||||
base := "/api/repositories/"
|
base := "/api/repositories/"
|
||||||
desc := struct {
|
desc := struct {
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
@ -307,7 +328,7 @@ func TestPutOfRepository(t *testing.T) {
|
|||||||
|
|
||||||
// verify that the description is changed
|
// verify that the description is changed
|
||||||
repositories := []*repoResp{}
|
repositories := []*repoResp{}
|
||||||
err := handleAndParse(&testingRequest{
|
err = handleAndParse(&testingRequest{
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
url: base,
|
url: base,
|
||||||
queryStruct: struct {
|
queryStruct: struct {
|
||||||
|
@ -35,45 +35,6 @@ import (
|
|||||||
uiutils "github.com/vmware/harbor/src/ui/utils"
|
uiutils "github.com/vmware/harbor/src/ui/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
//sysadmin has all privileges to all projects
|
|
||||||
func listRoles(userID int, projectID int64, entityType string) ([]models.Role, error) {
|
|
||||||
roles := make([]models.Role, 0, 1)
|
|
||||||
isSysAdmin, err := dao.IsAdminRole(userID)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to determine whether the user %d is system admin: %v", userID, err)
|
|
||||||
return roles, err
|
|
||||||
}
|
|
||||||
if isSysAdmin {
|
|
||||||
role, err := dao.GetRoleByID(models.PROJECTADMIN)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to get role %d: %v", models.PROJECTADMIN, err)
|
|
||||||
return roles, err
|
|
||||||
}
|
|
||||||
roles = append(roles, *role)
|
|
||||||
return roles, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
rs, err := dao.GetUserProjectRoles(userID, projectID, entityType)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to get user %d 's roles for project %d: %v", userID, projectID, err)
|
|
||||||
return roles, err
|
|
||||||
}
|
|
||||||
roles = append(roles, rs...)
|
|
||||||
return roles, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkUserExists(name string) int {
|
|
||||||
u, err := dao.GetUser(models.User{Username: name})
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error occurred in GetUser, error: %v", err)
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
if u != nil {
|
|
||||||
return u.UserID
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// SyncRegistry syncs the repositories of registry with database.
|
// SyncRegistry syncs the repositories of registry with database.
|
||||||
func SyncRegistry(pm promgr.ProjectManager) error {
|
func SyncRegistry(pm promgr.ProjectManager) error {
|
||||||
|
|
||||||
|
@ -46,6 +46,11 @@ func (d *Auth) SearchUser(username string) (*models.User, error) {
|
|||||||
return dao.GetUser(queryCondition)
|
return dao.GetUser(queryCondition)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnBoardUser -
|
||||||
|
func (d *Auth) OnBoardUser(u *models.User) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
auth.Register("db_auth", &Auth{})
|
auth.Register("db_auth", &Auth{})
|
||||||
}
|
}
|
||||||
|
@ -46,8 +46,7 @@ func initRouters() {
|
|||||||
beego.Router("/sendEmail", &controllers.CommonController{}, "get:SendResetEmail")
|
beego.Router("/sendEmail", &controllers.CommonController{}, "get:SendResetEmail")
|
||||||
|
|
||||||
//API:
|
//API:
|
||||||
beego.Router("/api/projects/:pid([0-9]+)/members/?:mid", &api.ProjectUserMemberAPI{})
|
beego.Router("/api/projects/:pid([0-9]+)/members/?:pmid([0-9]+)", &api.ProjectMemberAPI{})
|
||||||
beego.Router("/api/projects/:pid([0-9]+)/projectmembers/?:pmid([0-9]+)", &api.ProjectMemberAPI{})
|
|
||||||
beego.Router("/api/projects/", &api.ProjectAPI{}, "head:Head")
|
beego.Router("/api/projects/", &api.ProjectAPI{}, "head:Head")
|
||||||
beego.Router("/api/projects/:id([0-9]+)", &api.ProjectAPI{})
|
beego.Router("/api/projects/:id([0-9]+)", &api.ProjectAPI{})
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ export class ConfirmationDialogComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
operate(): void {
|
operate(): void {
|
||||||
if (!this.message){//Inproper condition
|
if (!this.message) {// Inproper condition
|
||||||
this.close();
|
this.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -120,7 +120,7 @@ export class ConfirmationDialogComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
confirm(): void {
|
confirm(): void {
|
||||||
if (!this.message){//Inproper condition
|
if (!this.message) {// Inproper condition
|
||||||
this.close();
|
this.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ import {Observable} from "rxjs/Observable";
|
|||||||
})
|
})
|
||||||
export class ListReplicationRuleComponent implements OnInit, OnChanges {
|
export class ListReplicationRuleComponent implements OnInit, OnChanges {
|
||||||
|
|
||||||
nullTime: string = '0001-01-01T00:00:00Z';
|
nullTime = '0001-01-01T00:00:00Z';
|
||||||
|
|
||||||
@Input() projectId: number;
|
@Input() projectId: number;
|
||||||
@Input() isSystemAdmin: boolean;
|
@Input() isSystemAdmin: boolean;
|
||||||
@ -72,7 +72,7 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
|
|||||||
@Output() openNewRule = new EventEmitter<any>();
|
@Output() openNewRule = new EventEmitter<any>();
|
||||||
@Output() replicateManual = new EventEmitter<ReplicationRule[]>();
|
@Output() replicateManual = new EventEmitter<ReplicationRule[]>();
|
||||||
|
|
||||||
projectScope: boolean = false;
|
projectScope = false;
|
||||||
|
|
||||||
rules: ReplicationRule[];
|
rules: ReplicationRule[];
|
||||||
changedRules: ReplicationRule[];
|
changedRules: ReplicationRule[];
|
||||||
@ -108,7 +108,7 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
//Global scope
|
// Global scope
|
||||||
if (!this.projectScope) {
|
if (!this.projectScope) {
|
||||||
this.retrieveRules();
|
this.retrieveRules();
|
||||||
}
|
}
|
||||||
@ -120,15 +120,15 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
|
|||||||
if (proIdChange.currentValue !== proIdChange.previousValue) {
|
if (proIdChange.currentValue !== proIdChange.previousValue) {
|
||||||
if (proIdChange.currentValue) {
|
if (proIdChange.currentValue) {
|
||||||
this.projectId = proIdChange.currentValue;
|
this.projectId = proIdChange.currentValue;
|
||||||
this.projectScope = true; //Scope is project, not global list
|
this.projectScope = true; // Scope is project, not global list
|
||||||
//Initially load the replication rule data
|
// Initially load the replication rule data
|
||||||
this.retrieveRules();
|
this.retrieveRules();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
retrieveRules(ruleName: string = ''): void {
|
retrieveRules(ruleName = ''): void {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
/*this.selectedRow = null;*/
|
/*this.selectedRow = null;*/
|
||||||
toPromise<ReplicationRule[]>(this.replicationService
|
toPromise<ReplicationRule[]>(this.replicationService
|
||||||
@ -184,7 +184,7 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
|
|||||||
jobList(id: string | number): Promise<void> {
|
jobList(id: string | number): Promise<void> {
|
||||||
let ruleData: ReplicationJobItem[];
|
let ruleData: ReplicationJobItem[];
|
||||||
this.canDeleteRule = true;
|
this.canDeleteRule = true;
|
||||||
let count: number = 0;
|
let count = 0;
|
||||||
return toPromise<ReplicationJob>(this.replicationService
|
return toPromise<ReplicationJob>(this.replicationService
|
||||||
.getJobs(id))
|
.getJobs(id))
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
@ -58,7 +58,7 @@ describe('RecentLogComponent (inline template)', () => {
|
|||||||
serviceConfig = TestBed.get(SERVICE_CONFIG);
|
serviceConfig = TestBed.get(SERVICE_CONFIG);
|
||||||
logService = fixture.debugElement.injector.get(AccessLogService);
|
logService = fixture.debugElement.injector.get(AccessLogService);
|
||||||
|
|
||||||
//Mock data
|
// Mock data
|
||||||
for (let i = 0; i < 18; i++) {
|
for (let i = 0; i < 18; i++) {
|
||||||
let item: AccessLogItem = {
|
let item: AccessLogItem = {
|
||||||
log_id: 23 + i,
|
log_id: 23 + i,
|
||||||
@ -80,7 +80,7 @@ describe('RecentLogComponent (inline template)', () => {
|
|||||||
if (params && params.get('repository')) {
|
if (params && params.get('repository')) {
|
||||||
return Promise.resolve(mockData2);
|
return Promise.resolve(mockData2);
|
||||||
} else {
|
} else {
|
||||||
if (params.get('page') == '1') {
|
if (params.get('page') === '1') {
|
||||||
mockData.data = mockItems.slice(0, 15);
|
mockData.data = mockItems.slice(0, 15);
|
||||||
} else {
|
} else {
|
||||||
mockData.data = mockItems.slice(15, 18)
|
mockData.data = mockItems.slice(15, 18)
|
||||||
@ -205,7 +205,7 @@ describe('RecentLogComponent (inline template)', () => {
|
|||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
let els: HTMLElement[] = fixture.nativeElement.querySelectorAll('.datagrid-row');
|
els = fixture.nativeElement.querySelectorAll('.datagrid-row');
|
||||||
expect(els).toBeTruthy();
|
expect(els).toBeTruthy();
|
||||||
expect(els.length).toEqual(16);
|
expect(els.length).toEqual(16);
|
||||||
});
|
});
|
||||||
|
@ -13,7 +13,7 @@ export abstract class SystemInfoService {
|
|||||||
/**
|
/**
|
||||||
* Get global system information.
|
* Get global system information.
|
||||||
* @abstract
|
* @abstract
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
abstract getSystemInfo(): Observable<SystemInfo> | Promise<SystemInfo> | SystemInfo;
|
abstract getSystemInfo(): Observable<SystemInfo> | Promise<SystemInfo> | SystemInfo;
|
||||||
}
|
}
|
||||||
@ -23,14 +23,14 @@ export class SystemInfoDefaultService extends SystemInfoService {
|
|||||||
constructor(
|
constructor(
|
||||||
@Inject(SERVICE_CONFIG) private config: IServiceConfig,
|
@Inject(SERVICE_CONFIG) private config: IServiceConfig,
|
||||||
private http: Http) {
|
private http: Http) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
getSystemInfo(): Observable<SystemInfo> | Promise<SystemInfo> | SystemInfo {
|
getSystemInfo(): Observable<SystemInfo> | Promise<SystemInfo> | SystemInfo {
|
||||||
let url = this.config.systemInfoEndpoint ? this.config.systemInfoEndpoint : '/api/systeminfo';
|
let url = this.config.systemInfoEndpoint ? this.config.systemInfoEndpoint : '/api/systeminfo';
|
||||||
return this.http.get(url, HTTP_GET_OPTIONS)
|
return this.http.get(url, HTTP_GET_OPTIONS)
|
||||||
.toPromise()
|
.toPromise()
|
||||||
.then(systemInfo=>systemInfo.json() as SystemInfo)
|
.then(systemInfo => systemInfo.json() as SystemInfo)
|
||||||
.catch(error=>Promise.reject(error));
|
.catch(error => Promise.reject(error));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<label for="member_name" class="col-md-4 form-group-label-override required">{{'MEMBER.NAME' | translate}}</label>
|
<label for="member_name" class="col-md-4 form-group-label-override required">{{'MEMBER.NAME' | translate}}</label>
|
||||||
<label for="member_name" aria-haspopup="true" role="tooltip" [class.invalid]="!isMemberNameValid"
|
<label for="member_name" aria-haspopup="true" role="tooltip" [class.invalid]="!isMemberNameValid"
|
||||||
class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" (mouseleave)="leaveInput()">
|
class="tooltip tooltip-validation tooltip-md tooltip-bottom-left" (mouseleave)="leaveInput()">
|
||||||
<input type="text" id="member_name" [(ngModel)]="member.username"
|
<input type="text" id="member_name" [(ngModel)]="member.entity_name"
|
||||||
name="member_name"
|
name="member_name"
|
||||||
size="20"
|
size="20"
|
||||||
#memberName="ngModel"
|
#memberName="ngModel"
|
||||||
|
@ -108,7 +108,7 @@ export class AddMemberComponent implements AfterViewChecked, OnInit, OnDestroy {
|
|||||||
this.memberService
|
this.memberService
|
||||||
.listMembers(this.projectId, cont.value).toPromise()
|
.listMembers(this.projectId, cont.value).toPromise()
|
||||||
.then((members: Member[]) => {
|
.then((members: Member[]) => {
|
||||||
if (members.filter(m => { return m.username === cont.value }).length > 0) {
|
if (members.filter(m => { return m.entity_name === cont.value }).length > 0) {
|
||||||
this.isMemberNameValid = false;
|
this.isMemberNameValid = false;
|
||||||
this.memberTooltip = 'MEMBER.USERNAME_ALREADY_EXISTS';
|
this.memberTooltip = 'MEMBER.USERNAME_ALREADY_EXISTS';
|
||||||
}
|
}
|
||||||
@ -145,9 +145,9 @@ export class AddMemberComponent implements AfterViewChecked, OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onSubmit(): void {
|
onSubmit(): void {
|
||||||
if (!this.member.username || this.member.username.length === 0) { return; }
|
if (!this.member.entity_name || this.member.entity_name.length === 0) { return; }
|
||||||
this.memberService
|
this.memberService
|
||||||
.addMember(this.projectId, this.member.username, +this.member.role_id)
|
.addMember(this.projectId, this.member.entity_name, +this.member.role_id)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
response => {
|
response => {
|
||||||
this.messageHandlerService.showSuccess('MEMBER.ADDED_SUCCESS');
|
this.messageHandlerService.showSuccess('MEMBER.ADDED_SUCCESS');
|
||||||
@ -185,7 +185,7 @@ export class AddMemberComponent implements AfterViewChecked, OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
selectedName(username: string) {
|
selectedName(username: string) {
|
||||||
this.member.username = username;
|
this.member.entity_name = username;
|
||||||
this.selectUserName = [];
|
this.selectUserName = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +230,7 @@ export class AddMemberComponent implements AfterViewChecked, OnInit, OnDestroy {
|
|||||||
this.addMemberOpened = true;
|
this.addMemberOpened = true;
|
||||||
this.hasChanged = false;
|
this.hasChanged = false;
|
||||||
this.member.role_id = 1;
|
this.member.role_id = 1;
|
||||||
this.member.username = '';
|
this.member.entity_name = '';
|
||||||
this.isMemberNameValid = true;
|
this.isMemberNameValid = true;
|
||||||
this.memberTooltip = 'MEMBER.USERNAME_IS_REQUIRED';
|
this.memberTooltip = 'MEMBER.USERNAME_IS_REQUIRED';
|
||||||
this.selectUserName = [];
|
this.selectUserName = [];
|
||||||
|
@ -32,10 +32,10 @@
|
|||||||
<clr-dg-column>{{'MEMBER.NAME' | translate}}</clr-dg-column>
|
<clr-dg-column>{{'MEMBER.NAME' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column>{{'MEMBER.ROLE' | translate}}</clr-dg-column>
|
<clr-dg-column>{{'MEMBER.ROLE' | translate}}</clr-dg-column>
|
||||||
<clr-dg-row *clrDgItems="let m of members" [clrDgItem]="m">
|
<clr-dg-row *clrDgItems="let m of members" [clrDgItem]="m">
|
||||||
<clr-dg-cell>{{m.username}}</clr-dg-cell>
|
<clr-dg-cell>{{m.entity_name}}</clr-dg-cell>
|
||||||
<clr-dg-cell>
|
<clr-dg-cell>
|
||||||
<span *ngIf="ChangeRoleOngoing(m.username)" class="spinner spinner-inline"> Loading... </span>
|
<span *ngIf="ChangeRoleOngoing(m.entity_name)" class="spinner spinner-inline"> Loading... </span>
|
||||||
<span *ngIf="!ChangeRoleOngoing(m.username)">{{roleInfo[m.role_id] | translate}}</span>
|
<span *ngIf="!ChangeRoleOngoing(m.entity_name)">{{roleInfo[m.role_id] | translate}}</span>
|
||||||
</clr-dg-cell>
|
</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>
|
<clr-dg-footer>
|
||||||
|
@ -135,7 +135,7 @@ export class MemberComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get onlySelf(): boolean {
|
get onlySelf(): boolean {
|
||||||
if (this.selectedRow.length === 1 && this.selectedRow[0].user_id === this.currentUser.user_id) {
|
if (this.selectedRow.length === 1 && this.selectedRow[0].id === this.currentUser.user_id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -149,9 +149,9 @@ export class MemberComponent implements OnInit, OnDestroy {
|
|||||||
let nameArr: string[] = [];
|
let nameArr: string[] = [];
|
||||||
this.batchActionInfos = [];
|
this.batchActionInfos = [];
|
||||||
m.forEach(data => {
|
m.forEach(data => {
|
||||||
nameArr.push(data.username);
|
nameArr.push(data.entity_name);
|
||||||
let initBatchMessage = new BatchInfo();
|
let initBatchMessage = new BatchInfo();
|
||||||
initBatchMessage.name = data.username;
|
initBatchMessage.name = data.entity_name;
|
||||||
this.batchActionInfos.push(initBatchMessage);
|
this.batchActionInfos.push(initBatchMessage);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -163,14 +163,14 @@ export class MemberComponent implements OnInit, OnDestroy {
|
|||||||
if (members && members.length) {
|
if (members && members.length) {
|
||||||
let promiseList: any[] = [];
|
let promiseList: any[] = [];
|
||||||
members.forEach(member => {
|
members.forEach(member => {
|
||||||
if (member.user_id === this.currentUser.user_id) {
|
if (member.id === this.currentUser.user_id) {
|
||||||
let foundMember = this.batchActionInfos.find(batchInfo => batchInfo.name === member.username);
|
let foundMember = this.batchActionInfos.find(batchInfo => batchInfo.name === member.entity_name);
|
||||||
this.translate.get("BATCH.SWITCH_FAILURE").subscribe(res => {
|
this.translate.get("BATCH.SWITCH_FAILURE").subscribe(res => {
|
||||||
this.messageHandlerService.handleError(res + ": " + foundMember.name);
|
this.messageHandlerService.handleError(res + ": " + foundMember.name);
|
||||||
foundMember = BathInfoChanges(foundMember, res, false, true);
|
foundMember = BathInfoChanges(foundMember, res, false, true);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
promiseList.push(this.changeOperate(this.projectId, member.user_id, this.roleNum, member.username));
|
promiseList.push(this.changeOperate(this.projectId, member.id, this.roleNum, member.entity_name));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -216,9 +216,9 @@ export class MemberComponent implements OnInit, OnDestroy {
|
|||||||
this.batchDeletionInfos = [];
|
this.batchDeletionInfos = [];
|
||||||
if (m && m.length) {
|
if (m && m.length) {
|
||||||
m.forEach(data => {
|
m.forEach(data => {
|
||||||
nameArr.push(data.username);
|
nameArr.push(data.entity_name);
|
||||||
let initBatchMessage = new BatchInfo ();
|
let initBatchMessage = new BatchInfo ();
|
||||||
initBatchMessage.name = data.username;
|
initBatchMessage.name = data.entity_name;
|
||||||
this.batchDeletionInfos.push(initBatchMessage);
|
this.batchDeletionInfos.push(initBatchMessage);
|
||||||
});
|
});
|
||||||
this.OperateDialogService.addBatchInfoList(this.batchDeletionInfos);
|
this.OperateDialogService.addBatchInfoList(this.batchDeletionInfos);
|
||||||
@ -239,13 +239,13 @@ export class MemberComponent implements OnInit, OnDestroy {
|
|||||||
if (members && members.length) {
|
if (members && members.length) {
|
||||||
let promiseLists: any[] = [];
|
let promiseLists: any[] = [];
|
||||||
members.forEach(member => {
|
members.forEach(member => {
|
||||||
if (member.user_id === this.currentUser.user_id) {
|
if (member.id === this.currentUser.user_id) {
|
||||||
let findedList = this.batchDeletionInfos.find(data => data.name === member.username);
|
let findedList = this.batchDeletionInfos.find(data => data.name === member.entity_name);
|
||||||
this.translate.get("BATCH.DELETED_FAILURE").subscribe(res => {
|
this.translate.get("BATCH.DELETED_FAILURE").subscribe(res => {
|
||||||
findedList = BathInfoChanges(findedList, res, false, true);
|
findedList = BathInfoChanges(findedList, res, false, true);
|
||||||
});
|
});
|
||||||
}else {
|
}else {
|
||||||
promiseLists.push(this.delOperate(this.projectId, member.user_id, member.username));
|
promiseLists.push(this.delOperate(this.projectId, member.id, member.entity_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -24,34 +24,34 @@ import {HTTP_JSON_OPTIONS, HTTP_GET_OPTIONS} from "../../shared/shared.utils";
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MemberService {
|
export class MemberService {
|
||||||
|
|
||||||
constructor(private http: Http) {}
|
constructor(private http: Http) {}
|
||||||
|
|
||||||
listMembers(projectId: number, username: string): Observable<Member[]> {
|
listMembers(projectId: number, username: string): Observable<Member[]> {
|
||||||
return this.http
|
return this.http
|
||||||
.get(`/api/projects/${projectId}/members?username=${username}`, HTTP_GET_OPTIONS)
|
.get(`/api/projects/${projectId}/members`, HTTP_GET_OPTIONS)
|
||||||
.map(response=>response.json() as Member[])
|
.map(response => response.json() as Member[])
|
||||||
.catch(error=>Observable.throw(error));
|
.catch(error => Observable.throw(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
addMember(projectId: number, username: string, roleId: number): Observable<any> {
|
addMember(projectId: number, username: string, roleId: number): Observable<any> {
|
||||||
return this.http
|
return this.http
|
||||||
.post(`/api/projects/${projectId}/members`, { username: username, roles: [ roleId ] }, HTTP_JSON_OPTIONS)
|
.post(`/api/projects/${projectId}/members`, { role_id: roleId, member_user: {username: username} }, HTTP_JSON_OPTIONS)
|
||||||
.map(response=>response.status)
|
.map(response => response.status)
|
||||||
.catch(error=>Observable.throw(error));
|
.catch(error => Observable.throw(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
changeMemberRole(projectId: number, userId: number, roleId: number): Promise<any> {
|
changeMemberRole(projectId: number, userId: number, roleId: number): Promise<any> {
|
||||||
return this.http
|
return this.http
|
||||||
.put(`/api/projects/${projectId}/members/${userId}`, { roles: [ roleId ]}, HTTP_JSON_OPTIONS).toPromise()
|
.put(`/api/projects/${projectId}/members/${userId}`, { role_id: roleId }, HTTP_JSON_OPTIONS).toPromise()
|
||||||
.then(response=>response.status)
|
.then(response => response.status)
|
||||||
.catch(error=>Promise.reject(error));
|
.catch(error => Promise.reject(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteMember(projectId: number, userId: number): Promise<any> {
|
deleteMember(projectId: number, userId: number): Promise<any> {
|
||||||
return this.http
|
return this.http
|
||||||
.delete(`/api/projects/${projectId}/members/${userId}`).toPromise()
|
.delete(`/api/projects/${projectId}/members/${userId}`).toPromise()
|
||||||
.then(response=>response.status)
|
.then(response => response.status)
|
||||||
.catch(error=>Promise.reject(error));
|
.catch(error => Promise.reject(error));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -30,9 +30,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export class Member {
|
export class Member {
|
||||||
user_id: number;
|
id: number;
|
||||||
username: string;
|
project_id: number;
|
||||||
|
entity_name: string;
|
||||||
role_name: string;
|
role_name: string;
|
||||||
has_admin_role: number;
|
|
||||||
role_id: number;
|
role_id: number;
|
||||||
|
entity_id: number;
|
||||||
|
entity_type: string;
|
||||||
}
|
}
|
@ -42,7 +42,7 @@ export class ProjectRoutingResolver implements Resolve<Project>{
|
|||||||
if (currentUser) {
|
if (currentUser) {
|
||||||
let projectMembers = this.sessionService.getProjectMembers();
|
let projectMembers = this.sessionService.getProjectMembers();
|
||||||
if (projectMembers) {
|
if (projectMembers) {
|
||||||
let currentMember = projectMembers.find(m => m.user_id === currentUser.user_id);
|
let currentMember = projectMembers.find(m => m.entity_id === currentUser.user_id);
|
||||||
if (currentMember) {
|
if (currentMember) {
|
||||||
project.is_member = true;
|
project.is_member = true;
|
||||||
project.has_project_admin_role = (currentMember.role_name === 'projectAdmin');
|
project.has_project_admin_role = (currentMember.role_name === 'projectAdmin');
|
||||||
|
@ -47,32 +47,32 @@ export class TargetExistsValidatorDirective implements Validator, OnChanges {
|
|||||||
}
|
}
|
||||||
validate(control: AbstractControl): {[key: string]: any} {
|
validate(control: AbstractControl): {[key: string]: any} {
|
||||||
return this.valFn(control);
|
return this.valFn(control);
|
||||||
}
|
}
|
||||||
|
|
||||||
targetExistsValidator(target: string): ValidatorFn {
|
targetExistsValidator(target: string): ValidatorFn {
|
||||||
return (control: AbstractControl): {[key: string]: any} => {
|
return (control: AbstractControl): {[key: string]: any} => {
|
||||||
switch(target) {
|
switch (target) {
|
||||||
case 'PROJECT_NAME':
|
case 'PROJECT_NAME':
|
||||||
return new Promise(resolve=>{
|
return new Promise(resolve => {
|
||||||
this.projectService
|
this.projectService
|
||||||
.checkProjectExists(control.value)
|
.checkProjectExists(control.value)
|
||||||
.subscribe(res=>resolve({'targetExists': true}),error=>resolve(null));
|
.subscribe(res => resolve({'targetExists': true}),error=>resolve(null));
|
||||||
});
|
});
|
||||||
case 'MEMBER_NAME':
|
case 'MEMBER_NAME':
|
||||||
return new Promise(resolve=>{
|
return new Promise(resolve => {
|
||||||
this.memberService
|
this.memberService
|
||||||
.listMembers(this.projectId, control.value)
|
.listMembers(this.projectId, control.value)
|
||||||
.subscribe((members: Member[])=>{
|
.subscribe((members: Member[]) => {
|
||||||
return members.filter(m=>{
|
return members.filter(m => {
|
||||||
if(m.username === control.value) {
|
if (m.entity_name === control.value) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}).length > 0 ?
|
}).length > 0 ?
|
||||||
resolve({'targetExists': true}) : resolve(null);
|
resolve({'targetExists': true}) : resolve(null);
|
||||||
},error=>resolve(null));
|
}, error => resolve(null));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user