-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Workspaces settings/preferences page (#138)
* add settings and integrations page * add tabs * clean up settings * add timezone and website fields for workspaces * fix timezone * use react-hook-form * add api to update a workspace * frontend changes to support logo upload * allow for logo upload * add logo if existing * use logo everywhere * start working on preferences * add api for preferences * connect api * store and update workspaces communication preferences * fix tabs * fix compilation * add db tests and create preferences on signup * add workspace updating tests * add fetching preferences tests * add more http tests
- Loading branch information
Showing
52 changed files
with
2,536 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package malak | ||
|
||
import ( | ||
"errors" | ||
"net/http" | ||
"net/url" | ||
"strings" | ||
"time" | ||
|
||
"github.com/ayinke-llc/hermes" | ||
) | ||
|
||
var imageClient = &http.Client{ | ||
Timeout: time.Second * 3, | ||
} | ||
|
||
func IsImageFromURL(s string) (bool, error) { | ||
if hermes.IsStringEmpty(s) { | ||
return false, errors.New("please provide the url") | ||
} | ||
|
||
u, err := url.Parse(s) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
resp, err := imageClient.Get(u.String()) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
defer resp.Body.Close() | ||
|
||
// Read the first 512 bytes of the response body | ||
buffer := make([]byte, 512) | ||
_, err = resp.Body.Read(buffer) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
// Detect the MIME type using the first 512 bytes | ||
mimeType := http.DetectContentType(buffer) | ||
|
||
if strings.HasPrefix(mimeType, "image/") { | ||
return true, nil | ||
} | ||
|
||
return false, errors.New("url does not contain an image") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package malak | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestIsImageFromURL(t *testing.T) { | ||
|
||
tt := []struct { | ||
endpoint string | ||
hasError bool | ||
name string | ||
}{ | ||
{ | ||
name: "no url provided", | ||
hasError: true, | ||
endpoint: "", | ||
}, | ||
{ | ||
name: "bad url", | ||
hasError: true, | ||
endpoint: "http://localhost:44000", | ||
}, | ||
{ | ||
name: "google.com", | ||
hasError: true, | ||
endpoint: "https://google.com", | ||
}, | ||
{ | ||
name: "unsplash", | ||
hasError: false, | ||
endpoint: "https://images.unsplash.com/photo-1737467023078-a694673d7cb3", | ||
}, | ||
} | ||
|
||
for _, tc := range tt { | ||
|
||
t.Run(tc.name, func(t *testing.T) { | ||
r, err := IsImageFromURL(tc.endpoint) | ||
|
||
if tc.hasError { | ||
require.Error(t, err) | ||
return | ||
} | ||
|
||
require.True(t, r) | ||
require.NoError(t, err) | ||
}) | ||
} | ||
} |
2 changes: 2 additions & 0 deletions
2
...astore/postgres/migrations/20250127221605_add_website_and_timezone_to_workspaces.down.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
ALTER TABLE workspaces DROP COLUMN website; | ||
ALTER TABLE workspaces DROP COLUMN timezone; |
2 changes: 2 additions & 0 deletions
2
...atastore/postgres/migrations/20250127221605_add_website_and_timezone_to_workspaces.up.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
ALTER TABLE workspaces ADD COLUMN website TEXT DEFAULT '' NOT NULL; | ||
ALTER TABLE workspaces ADD COLUMN timezone TEXT DEFAULT 'UTC' NOT NULL; |
1 change: 1 addition & 0 deletions
1
internal/datastore/postgres/migrations/20250128140800_add_logourl_to_workspaces.down.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
ALTER TABLE workspaces DROP COLUMN logo_url; |
1 change: 1 addition & 0 deletions
1
internal/datastore/postgres/migrations/20250128140800_add_logourl_to_workspaces.up.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
ALTER TABLE workspaces ADD COLUMN logo_url TEXT DEFAULT '' NOT NULL; |
1 change: 1 addition & 0 deletions
1
internal/datastore/postgres/migrations/20250128153903_create_preferences_table.down.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
DROP TABLE preferences; |
10 changes: 10 additions & 0 deletions
10
internal/datastore/postgres/migrations/20250128153903_create_preferences_table.up.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
CREATE TABLE preferences ( | ||
id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), | ||
workspace_id uuid NOT NULL REFERENCES workspaces(id), | ||
billing jsonb NOT NULL DEFAULT '{}'::jsonb, | ||
communication jsonb NOT NULL DEFAULT '{}'::jsonb, | ||
|
||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
deleted_at TIMESTAMP WITH TIME ZONE | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package postgres | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/ayinke-llc/malak" | ||
"github.com/uptrace/bun" | ||
) | ||
|
||
type preferenceRepo struct { | ||
inner *bun.DB | ||
} | ||
|
||
func NewPreferenceRepository(inner *bun.DB) malak.PreferenceRepository { | ||
return &preferenceRepo{ | ||
inner: inner, | ||
} | ||
} | ||
|
||
func (w *preferenceRepo) Update(ctx context.Context, | ||
preferences *malak.Preference, | ||
) error { | ||
_, err := w.inner.NewUpdate(). | ||
Model(preferences). | ||
Where("id = ?", preferences.ID). | ||
Exec(ctx) | ||
return err | ||
} | ||
|
||
func (w *preferenceRepo) Get(ctx context.Context, | ||
workspace *malak.Workspace, | ||
) (*malak.Preference, error) { | ||
preferences := &malak.Preference{} | ||
|
||
err := w.inner.NewSelect(). | ||
Where("workspace_id = ?", workspace.ID). | ||
Model(preferences).Scan(ctx) | ||
|
||
return preferences, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package postgres | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/ayinke-llc/malak" | ||
"github.com/google/uuid" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestPreferences_Get(t *testing.T) { | ||
// create and fetch | ||
t.Run("create and fetch", func(t *testing.T) { | ||
|
||
client, teardownFunc := setupDatabase(t) | ||
defer teardownFunc() | ||
|
||
prefRepo := NewPreferenceRepository(client) | ||
|
||
repo := NewWorkspaceRepository(client) | ||
|
||
userRepo := NewUserRepository(client) | ||
|
||
planRepo := NewPlanRepository(client) | ||
|
||
// user from the fixtures | ||
user, err := userRepo.Get(context.Background(), &malak.FindUserOptions{ | ||
Email: "[email protected]", | ||
}) | ||
require.NoError(t, err) | ||
|
||
plan, err := planRepo.Get(context.Background(), &malak.FetchPlanOptions{ | ||
Reference: "prod_QmtErtydaJZymT", | ||
}) | ||
require.NoError(t, err) | ||
|
||
opts := &malak.CreateWorkspaceOptions{ | ||
User: user, | ||
Workspace: malak.NewWorkspace("oops", user, plan, malak.GenerateReference(malak.EntityTypeWorkspace)), | ||
} | ||
|
||
require.NoError(t, repo.Create(context.Background(), opts)) | ||
|
||
pref, err := prefRepo.Get(context.Background(), opts.Workspace) | ||
require.NoError(t, err) | ||
|
||
require.True(t, pref.Communication.EnableMarketing) | ||
require.True(t, pref.Communication.EnableProductUpdates) | ||
}) | ||
|
||
t.Run("no exists", func(t *testing.T) { | ||
|
||
client, teardownFunc := setupDatabase(t) | ||
defer teardownFunc() | ||
|
||
prefRepo := NewPreferenceRepository(client) | ||
|
||
_, err := prefRepo.Get(context.Background(), &malak.Workspace{ | ||
ID: uuid.New(), | ||
}) | ||
require.Error(t, err) | ||
}) | ||
} | ||
|
||
func TestPreferences_Update(t *testing.T) { | ||
|
||
client, teardownFunc := setupDatabase(t) | ||
defer teardownFunc() | ||
|
||
prefRepo := NewPreferenceRepository(client) | ||
|
||
repo := NewWorkspaceRepository(client) | ||
|
||
userRepo := NewUserRepository(client) | ||
|
||
planRepo := NewPlanRepository(client) | ||
|
||
// user from the fixtures | ||
user, err := userRepo.Get(context.Background(), &malak.FindUserOptions{ | ||
Email: "[email protected]", | ||
}) | ||
require.NoError(t, err) | ||
|
||
plan, err := planRepo.Get(context.Background(), &malak.FetchPlanOptions{ | ||
Reference: "prod_QmtErtydaJZymT", | ||
}) | ||
require.NoError(t, err) | ||
|
||
opts := &malak.CreateWorkspaceOptions{ | ||
User: user, | ||
Workspace: malak.NewWorkspace("oops", user, plan, malak.GenerateReference(malak.EntityTypeWorkspace)), | ||
} | ||
|
||
require.NoError(t, repo.Create(context.Background(), opts)) | ||
|
||
pref, err := prefRepo.Get(context.Background(), opts.Workspace) | ||
require.NoError(t, err) | ||
|
||
require.True(t, pref.Communication.EnableMarketing) | ||
require.True(t, pref.Communication.EnableProductUpdates) | ||
|
||
////////// | ||
// Update the pref now | ||
|
||
pref.Communication.EnableMarketing = false | ||
require.NoError(t, prefRepo.Update(context.Background(), pref)) | ||
|
||
newPref, err := prefRepo.Get(context.Background(), opts.Workspace) | ||
require.NoError(t, err) | ||
|
||
require.False(t, newPref.Communication.EnableMarketing) | ||
require.True(t, newPref.Communication.EnableProductUpdates) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.