Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: add notifications inbox db#16599

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
defelmnq merged 40 commits intomainfromnotif-inbox/int-334
Mar 3, 2025
Merged

feat: add notifications inbox db#16599

defelmnq merged 40 commits intomainfromnotif-inbox/int-334
Mar 3, 2025

Conversation

defelmnq
Copy link
Contributor

This PR is linkedto the following issue.

The objective is to create the DB layer and migration for the newCoder Inbox.

@defelmnqdefelmnq self-assigned thisFeb 18, 2025
@defelmnqdefelmnq marked this pull request as ready for reviewFebruary 21, 2025 07:01
titleTEXT NOT NULL,
content TEXT NOT NULL,
icon TEXT NOT NULL,
actions JSONB NOT NULL,
Copy link
Contributor

Choose a reason for hiding this comment

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

Given that you havetitle andcontent, I assume you're going to be accepting the fully rendered content (probably Markdown) of the notification in these fields. That means that CTAs will already be included incontent, I think. What role willactions play here?

Copy link
ContributorAuthor

@defelmnqdefelmnqFeb 21, 2025
edited
Loading

Choose a reason for hiding this comment

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

The idea was to generate the title, content and actions using aDispatcher methodsimilar to SMTP.
thepayload field contains everything to have these three elements.

The reason why I had in mind to keep the actions separated from the body is that , based on the client (VSCode for example) we will not be able to handle the actions the same way. If we integrate the actions in the body using markdown it will not be compatible with everything.

So we just return labels and associated URLs and each client can handle it their way.

wdyt ?

Copy link
Contributor

Choose a reason for hiding this comment

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

If we integrate the actions in the body using markdown it will not be compatible with everything.

I think this is how it's already done, so we may need to change some things around later.
For now let's go with this until we reach any blockers.

},
Resource: rbac.ResourceInboxNotification.WithID(uuid.New()).InOrg(orgID).WithOwner(currentUser.String()),
AuthorizeMap: map[bool][]hasAuthSubjects{
true: {owner, orgMemberMe, orgAdmin},
Copy link
Contributor

Choose a reason for hiding this comment

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

Why doesorgMemberMe have privileges topolicy.ActionCreate inbox notifications?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

From my RBAC understandingorgMemberMe is the current user.
Associatedto this part on the which we use thecurrentUser id.

In the definition of the ResourceInboxNotification, I assign thecurrentUser toInboxNotification using theWithOwner(currentUser.String()) method.

TL;DR -orgMemberMe is the owner of the resource in the test - and the owner of the resource should be able to access it.

Copy link
Member

Choose a reason for hiding this comment

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

I think we might wantmemberMe in here as well?

Copy link
Contributor

Choose a reason for hiding this comment

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

@defelmnq I understand why the current user should be able toread their own messages, but why should they be allowed tocreate new messages? That should be a system privilege.

Comment on lines 1 to 5
-- name: FetchUnreadInboxNotificationsByUserID :many
SELECT * FROM inbox_notifications WHERE user_id = $1 AND read_at IS NULL ORDER BY created_at DESC;

-- name: FetchInboxNotificationsByUserID :many
SELECT * FROM inbox_notifications WHERE user_id = $1 ORDER BY created_at DESC;
Copy link
Contributor

Choose a reason for hiding this comment

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

These queries are identical except forread_at IS NULL; rather parameteriseFetchInboxNotificationsByUserID so you can explicitly filter for read/unread, or neither.

FetchUnreadInboxNotificationsByUserIDFilteredByTemplatesAndTargets could be refactored out according to the same pattern, too.

johnstcn reacted with thumbs up emoji
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

As I tried to iterate here and from what I found on the internet - I can't find a way to achieve that with sqlc.

sqlc, with narg, allow to have null parameters and optional values, with default values if we want - here the objective is a bit different as we want to completely change the query and theWHERE clause based on if a parameter is present or not.

If you have more idea, I could check.

Copy link
Member

Choose a reason for hiding this comment

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

You can alternatively just write a custom query yourself (seecoderd/database/modelqueries.go) and not need to deal with sqlc's idiosyncracies.

id UUID PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
template_id UUID NOT NULL REFERENCES notification_templates(id) ON DELETE CASCADE,
targets UUID[],
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Targets do not reference a specific table.

Targets represent another entity which is connected to the notification - this field will be used to filter and search.

@@ -0,0 +1,15 @@
CREATE TABLE inbox_notifications (
id UUID PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

references the user that receives the notification.

},
Resource: rbac.ResourceInboxNotification.WithID(uuid.New()).InOrg(orgID).WithOwner(currentUser.String()),
AuthorizeMap: map[bool][]hasAuthSubjects{
true: {owner, orgMemberMe, orgAdmin},
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

From my RBAC understandingorgMemberMe is the current user.
Associatedto this part on the which we use thecurrentUser id.

In the definition of the ResourceInboxNotification, I assign thecurrentUser toInboxNotification using theWithOwner(currentUser.String()) method.

TL;DR -orgMemberMe is the owner of the resource in the test - and the owner of the resource should be able to access it.

@defelmnq
Copy link
ContributorAuthor

Update on the PR with some changes :

  • Naming for the DB methods has been changed to fit with the existing ones.
  • Added a new methodCountUnreadNotificationsByUserID which was missing
  • Added pagination to list methods

About the pagination - because of the way notifications can be pushed (in real-time , potentially a lot of notifs quickly) - I decided to paginate using IDs instead of an offset which would be hard to maintain.

Copy link
Member

@johnstcnjohnstcn left a comment

Choose a reason for hiding this comment

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

No blocking comments, some suggestions below.

},
Resource: rbac.ResourceInboxNotification.WithID(uuid.New()).InOrg(orgID).WithOwner(currentUser.String()),
AuthorizeMap: map[bool][]hasAuthSubjects{
true: {owner, orgMemberMe, orgAdmin},
Copy link
Member

Choose a reason for hiding this comment

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

I think we might wantmemberMe in here as well?

Comment on lines +46 to +47
-- name: CountUnreadInboxNotificationsByUserID :one
SELECT COUNT(*) FROM inbox_notifications WHERE user_id = $1 AND read_at IS NULL;
Copy link
Member

Choose a reason for hiding this comment

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

Where do we plan to use this query? If we're just displaying the unread notifications count in the UI, would it suffice to just calllen(GetUnreadInboxNotificationsByUserID()? My assumption is that the UI will be fetching unread notifications anyway.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

This query will be called in two cases :

  • An endpoint to get the number of unread notifications (without any notifications - just the count)
  • Whenever you want to list the number of notifications (unread or not, filtered or not) - we'll include theunread_count

-- name: GetUnreadInboxNotificationsByUserIDFilteredByTemplatesAndTargets :many
-- param user_id: The user ID
-- param templates: The template IDs to filter by - the template_id = ANY(@templates::UUID[]) condition checks if the template_id is in the @templates array
-- param targets: The target IDs to filter by - the targets @> COALESCE(@targets, ARRAY[]::UUID[]) condition checks if the targets array (from the DB) contains all the elements in the @targets array
Copy link
Member

Choose a reason for hiding this comment

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

As a caller, it's not really clear to me what kind of UUID a target should be without looking at example usages. Could this be reworded slightly to be clearer?

Copy link
Member

Choose a reason for hiding this comment

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

Obligatory reminder to double-check migration number before merging!

defelmnq reacted with laugh emoji
type InboxNotificationReadStatus string

const (
InboxNotificationReadStatusRead InboxNotificationReadStatus = "READ"
Copy link
Contributor

Choose a reason for hiding this comment

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

Rather create a SQL type for this to get automatic codegen
Nit: make this lowercase to match other types' values

ORDER BY created_at DESC
LIMIT (COALESCE(NULLIF(@limit_opt :: INT, 0), 25));

-- name: GetInboxNotificationsByUserIDFilteredByTemplatesAndTargets :many
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: for future-proofing, rather drop the specificity here in case we add more filter options later:

Suggested change
-- name:GetInboxNotificationsByUserIDFilteredByTemplatesAndTargets :many
-- name:GetFilteredInboxNotificationsByUserID :many

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Renamed ✅

},
Resource: rbac.ResourceInboxNotification.WithID(uuid.New()).InOrg(orgID).WithOwner(currentUser.String()),
AuthorizeMap: map[bool][]hasAuthSubjects{
true: {owner, orgMemberMe, orgAdmin},
Copy link
Contributor

Choose a reason for hiding this comment

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

@defelmnq I understand why the current user should be able toread their own messages, but why should they be allowed tocreate new messages? That should be a system privilege.

Copy link
Contributor

@dannykoppingdannykopping left a comment

Choose a reason for hiding this comment

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

LGTM 👍

@defelmnqdefelmnq merged commitc074f77 intomainMar 3, 2025
33 of 35 checks passed
@defelmnqdefelmnq deleted the notif-inbox/int-334 branchMarch 3, 2025 09:12
@github-actionsgithub-actionsbot locked and limited conversation to collaboratorsMar 3, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.
Reviewers

@dannykoppingdannykoppingdannykopping approved these changes

@johnstcnjohnstcnjohnstcn approved these changes

@mafredrimafredriAwaiting requested review from mafredri

@DanielleMaywoodDanielleMaywoodAwaiting requested review from DanielleMaywood

Assignees

@defelmnqdefelmnq

Labels
None yet
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

3 participants
@defelmnq@dannykopping@johnstcn

[8]ページ先頭

©2009-2025 Movatter.jp