forked from wangziqi/gongxue-base
feat: add user notification center
This commit is contained in:
@@ -1774,6 +1774,38 @@ async function testProfile() {
|
||||
'profile badges should expose auto score badge as unlocked',
|
||||
);
|
||||
|
||||
const badgeNotifications = await request('/api/profile/notifications', {
|
||||
query: { notificationType: 'badge_granted', status: 'unread', limit: 20 },
|
||||
});
|
||||
assert.ok(
|
||||
badgeNotifications.items?.some(item => item.metadata?.badgeId === ids.tenantCheckInBadge),
|
||||
'auto badge grant should create unread student notification',
|
||||
);
|
||||
assert.equal(
|
||||
badgeNotifications.summary?.unread >= 1,
|
||||
true,
|
||||
'profile notification summary should count unread notifications',
|
||||
);
|
||||
|
||||
const firstBadgeNotification = badgeNotifications.items?.find(item => item.metadata?.badgeId === ids.tenantCheckInBadge);
|
||||
const markedNotification = await request('/api/profile/notifications/status', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
notificationIds: [firstBadgeNotification.id],
|
||||
status: 'read',
|
||||
},
|
||||
});
|
||||
assert.equal(markedNotification.item?.updatedCount, 1, 'student should mark own notification as read');
|
||||
|
||||
const otherUserNotifications = await request('/api/profile/notifications', {
|
||||
userId: SECOND_STUDENT_USER_ID,
|
||||
query: { notificationType: 'badge_granted', limit: 20 },
|
||||
});
|
||||
assert.ok(
|
||||
!otherUserNotifications.items?.some(item => item.metadata?.badgeId === ids.tenantCheckInBadge),
|
||||
'another student must not see current student notifications',
|
||||
);
|
||||
|
||||
const feedback = await request('/api/profile/feedbacks', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
@@ -6572,6 +6604,16 @@ async function testTenantAdminOps() {
|
||||
assert.equal(grant.item?.badgeId, ids.tenantBadge, 'tenant admin should grant badge');
|
||||
assert.equal(grant.item?.userId, USER_ID, 'badge grant should target student');
|
||||
|
||||
const manualBadgeNotifications = await request('/api/profile/notifications', {
|
||||
query: { notificationType: 'badge_granted', limit: 50 },
|
||||
});
|
||||
assert.ok(
|
||||
manualBadgeNotifications.items?.some(
|
||||
item => item.metadata?.source === 'tenant_admin_badge_grant' && item.metadata?.badgeId === ids.tenantBadge,
|
||||
),
|
||||
'manual badge grant should create a student notification',
|
||||
);
|
||||
|
||||
const repeatedGrant = await request('/api/tenant-admin/badge-grants', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
method: 'POST',
|
||||
@@ -6684,6 +6726,38 @@ async function testTenantAdminOps() {
|
||||
'resolved feedback should auto grant feedback badge',
|
||||
);
|
||||
|
||||
const feedbackNotifications = await request('/api/profile/notifications', {
|
||||
query: { limit: 80 },
|
||||
});
|
||||
assert.ok(
|
||||
feedbackNotifications.items?.some(
|
||||
item => item.notificationType === 'feedback_status_updated' && item.sourceId === pendingFeedback.id && item.status === 'unread',
|
||||
),
|
||||
'feedback status update should create unread student notification',
|
||||
);
|
||||
assert.ok(
|
||||
feedbackNotifications.items?.some(
|
||||
item => item.notificationType === 'feedback_reward_granted' && item.sourceId === pendingFeedback.id,
|
||||
),
|
||||
'feedback reward should create student reward notification',
|
||||
);
|
||||
|
||||
const tenantUserNotifications = await request('/api/tenant-admin/user-notifications', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
query: { userId: USER_ID, notificationType: 'feedback_status_updated', limit: 20 },
|
||||
});
|
||||
assert.ok(
|
||||
tenantUserNotifications.items?.some(item => item.sourceId === pendingFeedback.id && item.userId === USER_ID),
|
||||
'tenant admin should inspect student notifications with permission',
|
||||
);
|
||||
|
||||
const tenantNotificationDenied = await request('/api/tenant-admin/user-notifications', {
|
||||
userId: TENANT_TEACHER_USER_ID,
|
||||
query: { userId: USER_ID, limit: 20 },
|
||||
expectStatus: 403,
|
||||
});
|
||||
assert.equal(tenantNotificationDenied.code, 'TENANT_PERMISSION_REQUIRED', 'tenant user notification list requires explicit permission');
|
||||
|
||||
const rewardEventsAfterResolve = await request('/api/profile/score-events', { query: { limit: 50 } });
|
||||
const rewardCountAfterResolve = rewardEventsAfterResolve.items?.filter(
|
||||
item => item.eventType === 'feedback_reward' && item.sourceId === pendingFeedback.id,
|
||||
@@ -6976,6 +7050,14 @@ async function testPointActivitiesAndExchange() {
|
||||
assert.equal(redeemed.item?.order?.itemId, ids.pointExchangeItem, 'exchange order should bind item');
|
||||
assert.ok(redeemed.item?.couponRedemption?.id, 'coupon exchange should create coupon redemption');
|
||||
|
||||
const exchangeNotifications = await request('/api/profile/notifications', {
|
||||
query: { notificationType: 'point_exchange_completed', status: 'unread', limit: 20 },
|
||||
});
|
||||
assert.ok(
|
||||
exchangeNotifications.items?.some(item => item.sourceId === redeemed.item?.order?.id && item.metadata?.itemId === ids.pointExchangeItem),
|
||||
'completed point exchange should create unread student notification',
|
||||
);
|
||||
|
||||
const repeatedRedeem = await request('/api/profile/exchange-items/redeem', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
@@ -7055,6 +7137,7 @@ async function testTenantMemberPermissionsAndAudit() {
|
||||
assert.ok(permissionMatrix.permissions?.some(item => item.key === 'marketing:write'), 'permission matrix should expose marketing permission');
|
||||
assert.ok(permissionMatrix.permissions?.some(item => item.key === 'marketing:points:read'), 'permission matrix should expose point marketing read permission');
|
||||
assert.ok(permissionMatrix.permissions?.some(item => item.key === 'marketing:points:write'), 'permission matrix should expose point marketing write permission');
|
||||
assert.ok(permissionMatrix.permissions?.some(item => item.key === 'notifications:read'), 'permission matrix should expose user notification read permission');
|
||||
assert.ok(permissionMatrix.permissions?.some(item => item.key === 'dashboard:read'), 'permission matrix should expose dashboard read permission');
|
||||
assert.ok(permissionMatrix.permissions?.some(item => item.key === 'roles:write'), 'permission matrix should expose role template permission');
|
||||
assert.ok(permissionMatrix.permissions?.some(item => item.key === 'badges:grant'), 'permission matrix should expose badge grant permission');
|
||||
|
||||
Reference in New Issue
Block a user