Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a42f108
feat(notifications): add company logo url when available for email no…
defelmnq Oct 2, 2024
1fa1271
feat(notifications): adapt tests with new labels
defelmnq Oct 3, 2024
2def52e
fix: revert changes on generated code version
defelmnq Oct 3, 2024
1b1a4c4
feat(notification): move logo_url and app_name logic to helpers funct…
defelmnq Oct 3, 2024
779260e
chore: remove unused GetLogoURL method from notifications store inter…
defelmnq Oct 3, 2024
1e6899f
fix: add better context and timeout for db related queries
defelmnq Oct 4, 2024
b552267
chore: lint
defelmnq Oct 4, 2024
73e07e9
feat(notifications): improve logo_url and app_name fetching moving it…
defelmnq Oct 16, 2024
70e23ae
feat(notifications): improve logo_url and app_name fetching moving it…
defelmnq Oct 16, 2024
2f620c9
feat(notifications): improve logo_url and app_name fetching moving it…
defelmnq Oct 16, 2024
fdcdf7b
feat(notifications): improve logo_url and app_name fetching moving it…
defelmnq Oct 16, 2024
9c6c105
feat(coderd): regenerate golden files
Oct 16, 2024
0c131a5
feat(notifications): working on tests for logo and app_name
defelmnq Oct 17, 2024
34d6611
feat(notifications): change helpers logic to be defined in the Dispat…
Oct 17, 2024
0a9a66a
feat(notifications): add golden file for custom appearance
Oct 17, 2024
bf558cb
feat(notifications): add golden file for custom appearance
Oct 17, 2024
a420f37
feat(notifications): work on tests
defelmnq Oct 18, 2024
51d8d33
feat(notifications): add golden file for custom appearance
defelmnq Oct 18, 2024
d492d09
feat(notifications): add golden file for custom appearance
defelmnq Oct 18, 2024
0c9c485
feat(notifications): add comment ent in tests for enterprise feature
defelmnq Oct 18, 2024
a6d4a0c
feat(coderd): remove unused call
defelmnq Oct 18, 2024
4c5cb3d
fix(notifications): improve tests and some nit fixes
defelmnq Oct 18, 2024
e419431
chore(retry): improve retry policy on fetcher
defelmnq Oct 18, 2024
a7fec66
Merge remote-tracking branch 'origin/main' into feat/notif-custom-logo
defelmnq Oct 21, 2024
8b766f6
improve errors handling
defelmnq Oct 22, 2024
157e086
improve errors handling
defelmnq Oct 22, 2024
790ff33
improve errors handling
defelmnq Oct 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat(notifications): add company logo url when available for email no…
…tifications
  • Loading branch information
defelmnq committed Oct 16, 2024
commit a42f1082f8082bd017f2d3e881bca86bdb362526
2 changes: 1 addition & 1 deletion coderd/database/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion coderd/database/querier.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion coderd/database/queries.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion coderd/notifications/dispatch/smtp/html.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<body style="margin: 0; padding: 0; font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; color: #020617; background: #f8fafc;">
<div style="max-width: 600px; margin: 20px auto; padding: 60px; border: 1px solid #e2e8f0; border-radius: 8px; background-color: #fff; text-align: left; font-size: 14px; line-height: 1.5;">
<div style="text-align: center;">
<img src="https://coder.com/coder-logo-horizontal.png" alt="Coder Logo" style="height: 40px;" />
<img src="{{ .Labels._logo_url }}" alt="Company Logo" style="height: 40px;" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we present also the company name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤓 Will add it and present some screenshots so we can iterate with the name.

</div>
<h1 style="text-align: center; font-size: 24px; font-weight: 400; margin: 8px 0 32px; line-height: 1.5;">
{{ .Labels._subject }}
Expand Down
18 changes: 18 additions & 0 deletions coderd/notifications/notifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package notifications

import (
"context"
"database/sql"
"encoding/json"
"errors"
"sync"
"text/template"

Expand All @@ -22,6 +24,10 @@ import (
"github.com/coder/coder/v2/coderd/database"
)

const (
notificationsDefaultLogoURL = "https://coder.com/coder-logo-horizontal.png"
)

// notifier is a consumer of the notifications_messages queue. It dequeues messages from that table and processes them
// through a pipeline of fetch -> prepare -> render -> acquire handler -> deliver.
type notifier struct {
Expand Down Expand Up @@ -223,6 +229,18 @@ func (n *notifier) prepare(ctx context.Context, msg database.AcquireNotification
return nil, xerrors.Errorf("failed to resolve handler %q", msg.Method)
}

logoURL, err := n.store.GetLogoURL(ctx)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
n.log.Error(ctx, "failed fetching logo url", slog.Error(err))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an interesting use case. Some customers prefer to use their company logos instead of Coder default one. I think we should rather fail fast the notifier flow than default to Coder logo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @mtojek @mafredri as you both raised this one. In case of errors I can :

  • add default values (seems we do not want to avoid displaying Coder information to customers that prefer not.)
  • skip the logo or name
  • retry the notification

As this situation means that we had a failure fetching data from the db, I don't know what is the preferred solution.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be an option to make it less awkward: #14935 (comment)

... and just retry.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Errors in retrieving the data from the db will cause the notification to fail, and it'll be automatically retried later.
If we have a persistent issue which causes the notifications to exceed their retry limit (5 by default) then that's actually a good signal that something is wrong.

}

if logoURL == "" {
//nolint:ineffassign // define to default value if unable to fetch one from db
logoURL = notificationsDefaultLogoURL
}

payload.Labels["_logo_url"] = logoURL
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking loud:

Logo URL does not seem to be a Label or Data. Maybe we need to introduce another property like Meta? Or just put it on the same level as title and body.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @mtojek here.

I don't think this should go into the payload. It's going to be the same for every notification, and if it's in the payload then we'll be storing the same URL for every notification.

Have a look at coderd/notifications/dispatch/smtp/html.gotmpl: you'll see {{ base_url }}. This is provided by a helper function, defined in cli/server.go`:

// templateHelpers builds a set of functions which can be called in templates.
// We build them here to avoid an import cycle by using coderd.Options in notifications.Manager.
// We can later use this to inject whitelabel fields when app name / logo URL are overridden. <----
func templateHelpers(options *coderd.Options) map[string]any {
	return map[string]any{
		"base_url":     func() string { return options.AccessURL.String() },
		"current_year": func() string { return strconv.Itoa(time.Now().Year()) },
	}
}

We should create a new helper which retrieves the logo instead, I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, indeed it makes complete sense 🙏

I modified the approach to have both logo_url and app_name defined in the templateHelpers managinf both the normal flow, default value, and error cases. Keen to have your opinion on it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super 👍


var title, body string
if title, err = render.GoTemplate(msg.TitleTemplate, payload, n.helpers); err != nil {
return nil, xerrors.Errorf("render title: %w", err)
Expand Down
2 changes: 2 additions & 0 deletions coderd/notifications/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ type Store interface {
FetchNewMessageMetadata(ctx context.Context, arg database.FetchNewMessageMetadataParams) (database.FetchNewMessageMetadataRow, error)
GetNotificationMessagesByStatus(ctx context.Context, arg database.GetNotificationMessagesByStatusParams) ([]database.NotificationMessage, error)
GetNotificationsSettings(ctx context.Context) (string, error)

GetLogoURL(ctx context.Context) (string, error)
}

// Handler is responsible for preparing and delivering a notification by a given method.
Expand Down