2018-06-11 13:13:19 +00:00
package resourcecontrols
import (
2019-11-12 23:41:42 +00:00
"errors"
2018-06-11 13:13:19 +00:00
"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"
2019-03-21 01:20:14 +00:00
"github.com/portainer/portainer/api"
2018-06-11 13:13:19 +00:00
)
type resourceControlCreatePayload struct {
2019-11-12 23:41:42 +00:00
ResourceID string
Type string
Public bool
AdministratorsOnly bool
Users [ ] int
Teams [ ] int
SubResourceIDs [ ] string
2018-06-11 13:13:19 +00:00
}
2020-07-07 21:57:52 +00:00
var (
errResourceControlAlreadyExists = errors . New ( "A resource control is already applied on this resource" ) //http/resourceControl
errInvalidResourceControlType = errors . New ( "Unsupported resource control type" ) //http/resourceControl
)
2018-06-11 13:13:19 +00:00
func ( payload * resourceControlCreatePayload ) Validate ( r * http . Request ) error {
if govalidator . IsNull ( payload . ResourceID ) {
2019-11-12 23:41:42 +00:00
return errors . New ( "invalid payload: invalid resource identifier" )
2018-06-11 13:13:19 +00:00
}
if govalidator . IsNull ( payload . Type ) {
2019-11-12 23:41:42 +00:00
return errors . New ( "invalid payload: invalid type" )
2018-06-11 13:13:19 +00:00
}
2019-11-12 23:41:42 +00:00
if len ( payload . Users ) == 0 && len ( payload . Teams ) == 0 && ! payload . Public && ! payload . AdministratorsOnly {
return errors . New ( "invalid payload: must specify Users, Teams, Public or AdministratorsOnly" )
}
if payload . Public && payload . AdministratorsOnly {
return errors . New ( "invalid payload: cannot set both public and administrators only flags to true" )
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 :
2020-07-07 21:57:52 +00:00
return & httperror . HandlerError { http . StatusBadRequest , "Invalid type value. Value must be one of: container, service, volume, network, secret, stack or config" , errInvalidResourceControlType }
2018-06-11 13:13:19 +00:00
}
2020-05-20 05:23:15 +00:00
rc , err := handler . DataStore . ResourceControl ( ) . ResourceControlByResourceIDAndType ( payload . ResourceID , resourceControlType )
2019-11-12 23:41:42 +00:00
if err != nil {
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 {
2020-07-07 21:57:52 +00:00
return & httperror . HandlerError { http . StatusConflict , "A resource control is already associated to this resource" , errResourceControlAlreadyExists }
2018-06-11 13:13:19 +00:00
}
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 {
2019-11-12 23:41:42 +00:00
ResourceID : payload . ResourceID ,
SubResourceIDs : payload . SubResourceIDs ,
Type : resourceControlType ,
Public : payload . Public ,
AdministratorsOnly : payload . AdministratorsOnly ,
UserAccesses : userAccesses ,
TeamAccesses : teamAccesses ,
2018-06-11 13:13:19 +00:00
}
2020-05-20 05:23:15 +00:00
err = handler . DataStore . ResourceControl ( ) . CreateResourceControl ( & resourceControl )
2018-06-11 13:13:19 +00:00
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to persist the resource control inside the database" , err }
}
return response . JSON ( w , resourceControl )
}