2018-06-11 13:13:19 +00:00
package resourcecontrols
import (
"net/http"
"github.com/asaskevich/govalidator"
2018-09-10 10:01:38 +00:00
httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response"
2018-06-11 13:13:19 +00:00
"github.com/portainer/portainer"
"github.com/portainer/portainer/http/security"
)
type resourceControlCreatePayload struct {
2018-08-19 05:57:28 +00:00
ResourceID string
Type string
Public bool
Users [ ] int
Teams [ ] int
SubResourceIDs [ ] string
2018-06-11 13:13:19 +00:00
}
func ( payload * resourceControlCreatePayload ) Validate ( r * http . Request ) error {
if govalidator . IsNull ( payload . ResourceID ) {
return portainer . Error ( "Invalid resource identifier" )
}
if govalidator . IsNull ( payload . Type ) {
return portainer . Error ( "Invalid type" )
}
2018-08-19 05:57:28 +00:00
if len ( payload . Users ) == 0 && len ( payload . Teams ) == 0 && ! payload . Public {
return portainer . Error ( "Invalid resource control declaration. Must specify Users, Teams or Public" )
2018-06-11 13:13:19 +00:00
}
return nil
}
// POST request on /api/resource_controls
func ( handler * Handler ) resourceControlCreate ( w http . ResponseWriter , r * http . Request ) * httperror . HandlerError {
var payload resourceControlCreatePayload
err := request . DecodeAndValidateJSONPayload ( r , & payload )
if err != nil {
return & httperror . HandlerError { http . StatusBadRequest , "Invalid request payload" , err }
}
var resourceControlType portainer . ResourceControlType
switch payload . Type {
case "container" :
resourceControlType = portainer . ContainerResourceControl
case "service" :
resourceControlType = portainer . ServiceResourceControl
case "volume" :
resourceControlType = portainer . VolumeResourceControl
case "network" :
resourceControlType = portainer . NetworkResourceControl
case "secret" :
resourceControlType = portainer . SecretResourceControl
case "stack" :
resourceControlType = portainer . StackResourceControl
case "config" :
resourceControlType = portainer . ConfigResourceControl
default :
return & httperror . HandlerError { http . StatusBadRequest , "Invalid type value. Value must be one of: container, service, volume, network, secret, stack or config" , portainer . ErrInvalidResourceControlType }
}
rc , err := handler . ResourceControlService . ResourceControlByResourceID ( payload . ResourceID )
2018-06-19 11:15:10 +00:00
if err != nil && err != portainer . ErrObjectNotFound {
2018-06-11 13:13:19 +00:00
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to retrieve resource controls from the database" , err }
}
if rc != nil {
return & httperror . HandlerError { http . StatusConflict , "A resource control is already associated to this resource" , portainer . ErrResourceControlAlreadyExists }
}
var userAccesses = make ( [ ] portainer . UserResourceAccess , 0 )
for _ , v := range payload . Users {
userAccess := portainer . UserResourceAccess {
UserID : portainer . UserID ( v ) ,
AccessLevel : portainer . ReadWriteAccessLevel ,
}
userAccesses = append ( userAccesses , userAccess )
}
var teamAccesses = make ( [ ] portainer . TeamResourceAccess , 0 )
for _ , v := range payload . Teams {
teamAccess := portainer . TeamResourceAccess {
TeamID : portainer . TeamID ( v ) ,
AccessLevel : portainer . ReadWriteAccessLevel ,
}
teamAccesses = append ( teamAccesses , teamAccess )
}
resourceControl := portainer . ResourceControl {
2018-08-19 05:57:28 +00:00
ResourceID : payload . ResourceID ,
SubResourceIDs : payload . SubResourceIDs ,
Type : resourceControlType ,
Public : payload . Public ,
UserAccesses : userAccesses ,
TeamAccesses : teamAccesses ,
2018-06-11 13:13:19 +00:00
}
securityContext , err := security . RetrieveRestrictedRequestContext ( r )
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to retrieve info from request context" , err }
}
if ! security . AuthorizedResourceControlCreation ( & resourceControl , securityContext ) {
return & httperror . HandlerError { http . StatusForbidden , "Permission denied to create a resource control for the specified resource" , portainer . ErrResourceAccessDenied }
}
err = handler . ResourceControlService . CreateResourceControl ( & resourceControl )
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to persist the resource control inside the database" , err }
}
return response . JSON ( w , resourceControl )
}