api/app.go
func updateApp(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	var ia inputApp
	err = ParseInput(r, &ia)
	if err != nil {
		return err
	}
	imageReset, _ := strconv.ParseBool(InputValue(r, "imageReset"))
	updateData := app.App{
		TeamOwner:      ia.TeamOwner,
		Plan:           appTypes.Plan{Name: ia.Plan},
		Pool:           ia.Pool,
		Description:    ia.Description,
		Router:         ia.Router,
		Tags:           ia.Tags,
		Platform:       InputValue(r, "platform"),
		UpdatePlatform: imageReset,
		RouterOpts:     ia.RouterOpts,
	}
	tags, _ := InputValues(r, "tag")
	updateData.Tags = append(updateData.Tags, tags...) // for compatibility
	appName := r.URL.Query().Get(":appname")
	a, err := getAppFromContext(appName, r)
	if err != nil {
		return err
	}
	var wantedPerms []*permission.PermissionScheme
	if updateData.Router != "" || len(updateData.RouterOpts) > 0 {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: "updating router was deprecated, please add the wanted router and remove the old one"}
	}
	if updateData.Description != "" {
		wantedPerms = append(wantedPerms, permission.PermAppUpdateDescription)
	}
	if len(updateData.Tags) > 0 {
		wantedPerms = append(wantedPerms, permission.PermAppUpdateTags)
	}
	if updateData.Plan.Name != "" {
		wantedPerms = append(wantedPerms, permission.PermAppUpdatePlan)
	}
	if updateData.Pool != "" {
		wantedPerms = append(wantedPerms, permission.PermAppUpdatePool)
	}
	if updateData.TeamOwner != "" {
		wantedPerms = append(wantedPerms, permission.PermAppUpdateTeamowner)
	}
	if updateData.Platform != "" {
		repo, _ := image.SplitImageName(updateData.Platform)
		platform, errPlat := servicemanager.Platform.FindByName(repo)
		if errPlat != nil {
			return errPlat
		}
		if platform.Disabled {
			canUsePlat := permission.Check(t, permission.PermPlatformUpdate) ||
				permission.Check(t, permission.PermPlatformCreate)
			if !canUsePlat {
				return &errors.HTTP{Code: http.StatusBadRequest, Message: appTypes.ErrInvalidPlatform.Error()}
			}
		}
		wantedPerms = append(wantedPerms, permission.PermAppUpdatePlatform)
		updateData.UpdatePlatform = true
	}
	if updateData.UpdatePlatform {
		wantedPerms = append(wantedPerms, permission.PermAppUpdateImageReset)
	}
	if len(wantedPerms) == 0 {
		msg := "Neither the description, tags, plan, pool, team owner or platform were set. You must define at least one."
		return &errors.HTTP{Code: http.StatusBadRequest, Message: msg}
	}
	for _, perm := range wantedPerms {
		allowed := permission.Check(t, perm,
			contextsForApp(&a)...,
		)
		if !allowed {
			return permission.ErrUnauthorized
		}
	}
	evt, err := event.New(&event.Opts{
		Target:     appTarget(appName),
		Kind:       permission.PermAppUpdate,
		Owner:      t,
		CustomData: event.FormToCustomData(InputFields(r)),
		Allowed:    event.Allowed(permission.PermAppReadEvents, contextsForApp(&a)...),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 30*time.Second, "")
	defer keepAliveWriter.Stop()
	w.Header().Set("Content-Type", "application/x-json-stream")
	writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)}
	evt.SetLogWriter(writer)
	err = a.Update(updateData, evt)
	if err == appTypes.ErrPlanNotFound {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	if _, ok := err.(*router.ErrRouterNotFound); ok {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	return err
}
func updateApp(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	var ia inputApp
	err = ParseInput(r, &ia)
	if err != nil {
		return err
	}
	imageReset, _ := strconv.ParseBool(InputValue(r, "imageReset"))
	updateData := app.App{
		TeamOwner:      ia.TeamOwner,
		Plan:           appTypes.Plan{Name: ia.Plan},
		Pool:           ia.Pool,
		Description:    ia.Description,
		Router:         ia.Router,
		Tags:           ia.Tags,
		Platform:       InputValue(r, "platform"),
		UpdatePlatform: imageReset,
		RouterOpts:     ia.RouterOpts,
	}
	tags, _ := InputValues(r, "tag")
	updateData.Tags = append(updateData.Tags, tags...) // for compatibility
	appName := r.URL.Query().Get(":appname")
	a, err := getAppFromContext(appName, r)
	if err != nil {
		return err
	}
	var wantedPerms []*permission.PermissionScheme
	if updateData.Router != "" || len(updateData.RouterOpts) > 0 {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: "updating router was deprecated, please add the wanted router and remove the old one"}
	}
	if updateData.Description != "" {
		wantedPerms = append(wantedPerms, permission.PermAppUpdateDescription)
	}
	if len(updateData.Tags) > 0 {
		wantedPerms = append(wantedPerms, permission.PermAppUpdateTags)
	}
	if updateData.Plan.Name != "" {
		wantedPerms = append(wantedPerms, permission.PermAppUpdatePlan)
	}
	if updateData.Pool != "" {
		wantedPerms = append(wantedPerms, permission.PermAppUpdatePool)
	}
	if updateData.TeamOwner != "" {
		wantedPerms = append(wantedPerms, permission.PermAppUpdateTeamowner)
	}
	if updateData.Platform != "" {
		repo, _ := image.SplitImageName(updateData.Platform)
		platform, errPlat := servicemanager.Platform.FindByName(repo)
		if errPlat != nil {
			return errPlat
		}
		if platform.Disabled {
			canUsePlat := permission.Check(t, permission.PermPlatformUpdate) ||
				permission.Check(t, permission.PermPlatformCreate)
			if !canUsePlat {
				return &errors.HTTP{Code: http.StatusBadRequest, Message: appTypes.ErrInvalidPlatform.Error()}
			}
		}
		wantedPerms = append(wantedPerms, permission.PermAppUpdatePlatform)
		updateData.UpdatePlatform = true
	}
	if updateData.UpdatePlatform {
		wantedPerms = append(wantedPerms, permission.PermAppUpdateImageReset)
	}
	if len(wantedPerms) == 0 {
		msg := "Neither the description, tags, plan, pool, team owner or platform were set. You must define at least one."
		return &errors.HTTP{Code: http.StatusBadRequest, Message: msg}
	}
	for _, perm := range wantedPerms {
		allowed := permission.Check(t, perm,
			contextsForApp(&a)...,
		)
		if !allowed {
			return permission.ErrUnauthorized
		}
	}
	evt, err := event.New(&event.Opts{
		Target:     appTarget(appName),
		Kind:       permission.PermAppUpdate,
		Owner:      t,
		CustomData: event.FormToCustomData(InputFields(r)),
		Allowed:    event.Allowed(permission.PermAppReadEvents, contextsForApp(&a)...),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 30*time.Second, "")
	defer keepAliveWriter.Stop()
	w.Header().Set("Content-Type", "application/x-json-stream")
	writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)}
	evt.SetLogWriter(writer)
	err = a.Update(updateData, evt)
	if err == appTypes.ErrPlanNotFound {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	if _, ok := err.(*router.ErrRouterNotFound); ok {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	return err
}
// title: app update
// path: /apps/{name}
// method: PUT
// consume: application/x-www-form-urlencoded
// produce: application/x-json-stream
// responses:
//   200: App updated
//   400: Invalid new pool
//   401: Unauthorized
//   404: Not found