forked from bluesky-social/atproto
-
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.
Notifications from the appview (bluesky-social#829)
* Update notif lexicons for stateless seenAt param * In-progress work on appview notifs * Fix-up bsky notification methods * Add appview notification table table * Process notifications in bsky appview, test notif indexing * Test bsky appview notification methods * Tidy bsky notification tests * Explicitly don't support seenAt notif params on pds * Tidy bsky notifs tests * Sync bsky notif handling with pds * Remove stale comment * Switch bsky notifs tests to use testenv
- Loading branch information
Showing
32 changed files
with
1,010 additions
and
201 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
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
35 changes: 35 additions & 0 deletions
35
packages/bsky/src/api/app/bsky/notification/getUnreadCount.ts
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,35 @@ | ||
import { Server } from '../../../../lexicon' | ||
import { countAll, notSoftDeletedClause } from '../../../../db/util' | ||
import AppContext from '../../../../context' | ||
import { authVerifier } from '../util' | ||
|
||
export default function (server: Server, ctx: AppContext) { | ||
server.app.bsky.notification.getUnreadCount({ | ||
auth: authVerifier, | ||
handler: async ({ auth, params }) => { | ||
const requester = auth.credentials.did | ||
const { seenAt } = params | ||
|
||
const { ref } = ctx.db.db.dynamic | ||
const result = await ctx.db.db | ||
.selectFrom('notification') | ||
.select(countAll.as('count')) | ||
.innerJoin('actor', 'actor.did', 'notification.did') | ||
.innerJoin('record', 'record.uri', 'notification.recordUri') | ||
.where(notSoftDeletedClause(ref('actor'))) | ||
.where(notSoftDeletedClause(ref('record'))) | ||
.where('notification.did', '=', requester) | ||
.if(!!seenAt, (qb) => | ||
qb.where('notification.sortAt', '>', String(seenAt)), | ||
) | ||
.executeTakeFirst() | ||
|
||
const count = result?.count ?? 0 | ||
|
||
return { | ||
encoding: 'application/json', | ||
body: { count }, | ||
} | ||
}, | ||
}) | ||
} |
87 changes: 87 additions & 0 deletions
87
packages/bsky/src/api/app/bsky/notification/listNotifications.ts
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,87 @@ | ||
import { jsonStringToLex } from '@atproto/lexicon' | ||
import { Server } from '../../../../lexicon' | ||
import { paginate, TimeCidKeyset } from '../../../../db/pagination' | ||
import AppContext from '../../../../context' | ||
import { notSoftDeletedClause } from '../../../../db/util' | ||
import { authVerifier } from '../util' | ||
|
||
export default function (server: Server, ctx: AppContext) { | ||
server.app.bsky.notification.listNotifications({ | ||
auth: authVerifier, | ||
handler: async ({ params, auth }) => { | ||
const { limit, cursor } = params | ||
const requester = auth.credentials.did | ||
const { seenAt } = params | ||
|
||
const { ref } = ctx.db.db.dynamic | ||
let notifBuilder = ctx.db.db | ||
.selectFrom('notification as notif') | ||
.innerJoin('record', 'record.uri', 'notif.recordUri') | ||
.innerJoin('actor as author', 'author.did', 'notif.author') | ||
.where(notSoftDeletedClause(ref('record'))) | ||
.where(notSoftDeletedClause(ref('author'))) | ||
.where('notif.did', '=', requester) | ||
.select([ | ||
'notif.recordUri as uri', | ||
'notif.recordCid as cid', | ||
'author.did as authorDid', | ||
'author.handle as authorHandle', | ||
'author.indexedAt as authorIndexedAt', | ||
'author.takedownId as authorTakedownId', | ||
'notif.reason as reason', | ||
'notif.reasonSubject as reasonSubject', | ||
'notif.sortAt as indexedAt', | ||
'record.json as recordJson', | ||
]) | ||
|
||
const keyset = new NotifsKeyset( | ||
ref('notif.sortAt'), | ||
ref('notif.recordCid'), | ||
) | ||
notifBuilder = paginate(notifBuilder, { | ||
cursor, | ||
limit, | ||
keyset, | ||
}) | ||
|
||
const notifs = await notifBuilder.execute() | ||
|
||
const actorService = ctx.services.actor(ctx.db) | ||
const authors = await actorService.views.profile( | ||
notifs.map((notif) => ({ | ||
did: notif.authorDid, | ||
handle: notif.authorHandle, | ||
indexedAt: notif.authorIndexedAt, | ||
takedownId: notif.authorTakedownId, | ||
})), | ||
requester, | ||
) | ||
|
||
const notifications = notifs.map((notif, i) => ({ | ||
uri: notif.uri, | ||
cid: notif.cid, | ||
author: authors[i], | ||
reason: notif.reason, | ||
reasonSubject: notif.reasonSubject || undefined, | ||
record: jsonStringToLex(notif.recordJson) as Record<string, unknown>, | ||
isRead: seenAt ? notif.indexedAt <= seenAt : false, | ||
indexedAt: notif.indexedAt, | ||
})) | ||
|
||
return { | ||
encoding: 'application/json', | ||
body: { | ||
notifications, | ||
cursor: keyset.packFromResult(notifs), | ||
}, | ||
} | ||
}, | ||
}) | ||
} | ||
|
||
type NotifRow = { indexedAt: string; cid: string } | ||
class NotifsKeyset extends TimeCidKeyset<NotifRow> { | ||
labelResult(result: NotifRow) { | ||
return { primary: result.indexedAt, secondary: result.cid } | ||
} | ||
} |
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
25 changes: 25 additions & 0 deletions
25
packages/bsky/src/db/migrations/20230408T152211201Z-notification-init.ts
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,25 @@ | ||
import { Kysely } from 'kysely' | ||
|
||
export async function up(db: Kysely<unknown>): Promise<void> { | ||
// Notifications | ||
await db.schema | ||
.createTable('notification') | ||
.addColumn('id', 'bigserial', (col) => col.primaryKey()) | ||
.addColumn('did', 'varchar', (col) => col.notNull()) | ||
.addColumn('recordUri', 'varchar', (col) => col.notNull()) | ||
.addColumn('recordCid', 'varchar', (col) => col.notNull()) | ||
.addColumn('author', 'varchar', (col) => col.notNull()) | ||
.addColumn('reason', 'varchar', (col) => col.notNull()) | ||
.addColumn('reasonSubject', 'varchar') | ||
.addColumn('sortAt', 'varchar', (col) => col.notNull()) | ||
.execute() | ||
await db.schema | ||
.createIndex('notification_did_sortat_idx') | ||
.on('notification') | ||
.columns(['did', 'sortAt']) | ||
.execute() | ||
} | ||
|
||
export async function down(db: Kysely<unknown>): Promise<void> { | ||
await db.schema.dropTable('notification').execute() | ||
} |
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,16 @@ | ||
import { Generated } from 'kysely' | ||
|
||
export const tableName = 'notification' | ||
|
||
export interface Notification { | ||
id: Generated<number> | ||
did: string | ||
recordUri: string | ||
recordCid: string | ||
author: string | ||
reason: string | ||
reasonSubject: string | null | ||
sortAt: string | ||
} | ||
|
||
export type PartialDB = { [tableName]: Notification } |
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
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 was deleted.
Oops, something went wrong.
Oops, something went wrong.