Skip to content

Commit 6d718e2

Browse files
committed
feat: add storage settings support
1 parent eb42f5e commit 6d718e2

File tree

4 files changed

+308
-5
lines changed

4 files changed

+308
-5
lines changed

docs/resources/settings.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,19 @@ resource "supabase_settings" "production" {
3939
mfa_phone_otp_length = 6
4040
sms_otp_length = 6
4141
})
42+
43+
storage = jsonencode({
44+
# fileSizeLimit is expressed in bytes (e.g., 50MB = 50 * 1024 * 1024)
45+
fileSizeLimit = 52428800
46+
features = {
47+
imageTransformation = {
48+
enabled = true
49+
}
50+
s3Protocol = {
51+
enabled = false
52+
}
53+
}
54+
})
4255
}
4356
```
4457

examples/resources/supabase_settings/resource.tf

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,17 @@ resource "supabase_settings" "production" {
2424
mfa_phone_otp_length = 6
2525
sms_otp_length = 6
2626
})
27+
28+
storage = jsonencode({
29+
# fileSizeLimit is expressed in bytes (e.g., 50MB = 50 * 1024 * 1024)
30+
fileSizeLimit = 52428800
31+
features = {
32+
imageTransformation = {
33+
enabled = true
34+
}
35+
s3Protocol = {
36+
enabled = false
37+
}
38+
}
39+
})
2740
}

internal/provider/settings_resource.go

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ func (r *SettingsResource) Create(ctx context.Context, req resource.CreateReques
145145
if !data.Auth.IsNull() {
146146
resp.Diagnostics.Append(updateAuthConfig(ctx, &data, r.client)...)
147147
}
148+
if !data.Storage.IsNull() {
149+
resp.Diagnostics.Append(updateStorageConfig(ctx, &data, r.client)...)
150+
}
148151
// TODO: update all settings above concurrently
149152
if resp.Diagnostics.HasError() {
150153
return
@@ -183,6 +186,9 @@ func (r *SettingsResource) Read(ctx context.Context, req resource.ReadRequest, r
183186
if !data.Auth.IsNull() {
184187
resp.Diagnostics.Append(readAuthConfig(ctx, &data, r.client)...)
185188
}
189+
if !data.Storage.IsNull() {
190+
resp.Diagnostics.Append(readStorageConfig(ctx, &data, r.client)...)
191+
}
186192
// TODO: read all settings above concurrently
187193
if resp.Diagnostics.HasError() {
188194
return
@@ -216,6 +222,9 @@ func (r *SettingsResource) Update(ctx context.Context, req resource.UpdateReques
216222
if !data.Auth.IsNull() {
217223
resp.Diagnostics.Append(updateAuthConfig(ctx, &data, r.client)...)
218224
}
225+
if !data.Storage.IsNull() {
226+
resp.Diagnostics.Append(updateStorageConfig(ctx, &data, r.client)...)
227+
}
219228
// TODO: update all settings above concurrently
220229
if resp.Diagnostics.HasError() {
221230
return
@@ -246,6 +255,7 @@ func (r *SettingsResource) ImportState(ctx context.Context, req resource.ImportS
246255
resp.Diagnostics.Append(readNetworkConfig(ctx, &data, r.client)...)
247256
resp.Diagnostics.Append(readApiConfig(ctx, &data, r.client)...)
248257
resp.Diagnostics.Append(readAuthConfig(ctx, &data, r.client)...)
258+
resp.Diagnostics.Append(readStorageConfig(ctx, &data, r.client)...)
249259

250260
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
251261
}
@@ -420,9 +430,25 @@ func pickConfig(source any, target map[string]any) {
420430
tag := t.Field(i).Tag.Get("json")
421431
k := strings.Split(tag, ",")[0]
422432
// Check that tag is picked by target
423-
if _, ok := target[k]; ok {
424-
target[k] = v.Field(i).Interface()
433+
targetVal, ok := target[k]
434+
if !ok {
435+
continue
436+
}
437+
sourceField := v.Field(i)
438+
// Recursively pick nested struct fields
439+
if targetMap, isMap := targetVal.(map[string]any); isMap {
440+
if sourceField.Kind() == reflect.Pointer {
441+
if sourceField.IsNil() {
442+
continue
443+
}
444+
sourceField = sourceField.Elem()
445+
}
446+
if sourceField.Kind() == reflect.Struct {
447+
pickConfig(sourceField.Interface(), targetMap)
448+
continue
449+
}
425450
}
451+
target[k] = sourceField.Interface()
426452
}
427453
}
428454

@@ -578,3 +604,52 @@ func updateNetworkConfig(ctx context.Context, plan *SettingsResourceModel, clien
578604
}
579605
return nil
580606
}
607+
608+
func readStorageConfig(ctx context.Context, state *SettingsResourceModel, client *api.ClientWithResponses) diag.Diagnostics {
609+
// Use ProjectRef if Id is not set (during Create), otherwise use Id (during Read/Import)
610+
projectRef := state.Id.ValueString()
611+
if projectRef == "" {
612+
projectRef = state.ProjectRef.ValueString()
613+
}
614+
615+
httpResp, err := client.V1GetStorageConfigWithResponse(ctx, projectRef)
616+
if err != nil {
617+
msg := fmt.Sprintf("Unable to read storage settings, got error: %s", err)
618+
return diag.Diagnostics{diag.NewErrorDiagnostic("Client Error", msg)}
619+
}
620+
// Deleted project is an orphan resource, not returning error so it can be destroyed.
621+
switch httpResp.StatusCode() {
622+
case http.StatusNotFound, http.StatusNotAcceptable:
623+
return nil
624+
}
625+
if httpResp.JSON200 == nil {
626+
msg := fmt.Sprintf("Unable to read storage settings, got status %d: %s", httpResp.StatusCode(), httpResp.Body)
627+
return diag.Diagnostics{diag.NewErrorDiagnostic("Client Error", msg)}
628+
}
629+
630+
if state.Storage, err = parseConfig(state.Storage, *httpResp.JSON200); err != nil {
631+
msg := fmt.Sprintf("Unable to read storage settings, got error: %s", err)
632+
return diag.Diagnostics{diag.NewErrorDiagnostic("Client Error", msg)}
633+
}
634+
return nil
635+
}
636+
637+
func updateStorageConfig(ctx context.Context, plan *SettingsResourceModel, client *api.ClientWithResponses) diag.Diagnostics {
638+
var body api.UpdateStorageConfigBody
639+
if diags := plan.Storage.Unmarshal(&body); diags.HasError() {
640+
return diags
641+
}
642+
643+
httpResp, err := client.V1UpdateStorageConfigWithResponse(ctx, plan.ProjectRef.ValueString(), body)
644+
if err != nil {
645+
msg := fmt.Sprintf("Unable to update storage settings, got error: %s", err)
646+
return diag.Diagnostics{diag.NewErrorDiagnostic("Client Error", msg)}
647+
}
648+
if httpResp.StatusCode() != http.StatusOK {
649+
msg := fmt.Sprintf("Unable to update storage settings, got status %d: %s", httpResp.StatusCode(), httpResp.Body)
650+
return diag.Diagnostics{diag.NewErrorDiagnostic("Client Error", msg)}
651+
}
652+
653+
// Read back the updated config to get the actual state with correct field names
654+
return readStorageConfig(ctx, plan, client)
655+
}

0 commit comments

Comments
 (0)