Browse Source

refactor(spec): introduce features.in_app_notification scope for notification data APIs

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ryotaro Nagahara 3 weeks ago
parent
commit
b3503f38af

+ 4 - 2
apps/app/public/static/locales/en_US/commons.json

@@ -171,7 +171,8 @@
         "share_link": "Grants permission to view share link features.",
         "share_link": "Grants permission to view share link features.",
         "bookmark": "Grants permission to view bookmark features.",
         "bookmark": "Grants permission to view bookmark features.",
         "attachment": "Grants permission to view attachment features.",
         "attachment": "Grants permission to view attachment features.",
-        "page_bulk_export": "Grants permission to view page bulk export features."
+        "page_bulk_export": "Grants permission to view page bulk export features.",
+        "in_app_notification": "Grants permission to view in-app notification features."
       }
       }
     },
     },
     "write": {
     "write": {
@@ -216,7 +217,8 @@
         "share_link": "Grants permission to edit share link features.",
         "share_link": "Grants permission to edit share link features.",
         "bookmark": "Grants permission to edit bookmark features.",
         "bookmark": "Grants permission to edit bookmark features.",
         "attachment": "Grants permission to edit attachment features.",
         "attachment": "Grants permission to edit attachment features.",
-        "page_bulk_export": "Grants permission to edit page bulk export features."
+        "page_bulk_export": "Grants permission to edit page bulk export features.",
+        "in_app_notification": "Grants permission to edit in-app notification features."
       }
       }
     }
     }
   }
   }

+ 4 - 2
apps/app/public/static/locales/fr_FR/commons.json

@@ -172,7 +172,8 @@
         "share_link": "Accorde la permission de voir les fonctionnalités de lien de partage.",
         "share_link": "Accorde la permission de voir les fonctionnalités de lien de partage.",
         "bookmark": "Accorde la permission de voir les fonctionnalités de signet.",
         "bookmark": "Accorde la permission de voir les fonctionnalités de signet.",
         "attachment": "Accorde la permission de voir les fonctionnalités de pièce jointe.",
         "attachment": "Accorde la permission de voir les fonctionnalités de pièce jointe.",
-        "page_bulk_export": "Accorde la permission de voir les fonctionnalités d'exportation en masse de pages."
+        "page_bulk_export": "Accorde la permission de voir les fonctionnalités d'exportation en masse de pages.",
+        "in_app_notification": "Accorde la permission de voir les fonctionnalités de notification intégrée à l'application."
       }
       }
     },
     },
     "write": {
     "write": {
@@ -217,7 +218,8 @@
         "share_link": "Accorde la permission de modifier les fonctionnalités de lien de partage.",
         "share_link": "Accorde la permission de modifier les fonctionnalités de lien de partage.",
         "bookmark": "Accorde la permission de modifier les fonctionnalités de signet.",
         "bookmark": "Accorde la permission de modifier les fonctionnalités de signet.",
         "attachment": "Accorde la permission de modifier les fonctionnalités de pièce jointe.",
         "attachment": "Accorde la permission de modifier les fonctionnalités de pièce jointe.",
-        "page_bulk_export": "Accorde la permission de modifier les fonctionnalités d'exportation en masse de pages."
+        "page_bulk_export": "Accorde la permission de modifier les fonctionnalités d'exportation en masse de pages.",
+        "in_app_notification": "Accorde la permission de modifier les fonctionnalités de notification intégrée à l'application."
       }
       }
     }
     }
   }
   }

+ 4 - 2
apps/app/public/static/locales/ja_JP/commons.json

@@ -175,7 +175,8 @@
         "share_link": "共有リンク機能の閲覧権限を付与できます。",
         "share_link": "共有リンク機能の閲覧権限を付与できます。",
         "bookmark": "ブックマーク機能の閲覧権限を付与できます。",
         "bookmark": "ブックマーク機能の閲覧権限を付与できます。",
         "attachment": "添付ファイル機能の閲覧権限を付与できます。",
         "attachment": "添付ファイル機能の閲覧権限を付与できます。",
-        "page_bulk_export": "ページの一括エクスポート機能の閲覧権限を付与できます。"
+        "page_bulk_export": "ページの一括エクスポート機能の閲覧権限を付与できます。",
+        "in_app_notification": "アプリ内通知機能の閲覧権限を付与できます。"
       }
       }
     },
     },
     "write": {
     "write": {
@@ -220,7 +221,8 @@
         "share_link": "共有リンク機能の編集権限を付与できます。",
         "share_link": "共有リンク機能の編集権限を付与できます。",
         "bookmark": "ブックマーク機能の編集権限を付与できます。",
         "bookmark": "ブックマーク機能の編集権限を付与できます。",
         "attachment": "添付ファイル機能の編集権限を付与できます。",
         "attachment": "添付ファイル機能の編集権限を付与できます。",
-        "page_bulk_export": "ページの一括エクスポート機能の編集権限を付与できます。"
+        "page_bulk_export": "ページの一括エクスポート機能の編集権限を付与できます。",
+        "in_app_notification": "アプリ内通知機能の編集権限を付与できます。"
       }
       }
     }
     }
   }
   }

+ 4 - 2
apps/app/public/static/locales/zh_CN/commons.json

@@ -174,7 +174,8 @@
         "share_link": "授予查看共享链接功能的权限。",
         "share_link": "授予查看共享链接功能的权限。",
         "bookmark": "授予查看书签功能的权限。",
         "bookmark": "授予查看书签功能的权限。",
         "attachment": "授予查看附件功能的权限。",
         "attachment": "授予查看附件功能的权限。",
-        "page_bulk_export": "授予查看页面批量导出功能的权限。"
+        "page_bulk_export": "授予查看页面批量导出功能的权限。",
+        "in_app_notification": "授予查看应用内通知功能的权限。"
       }
       }
     },
     },
     "write": {
     "write": {
@@ -219,7 +220,8 @@
         "share_link": "授予编辑共享链接功能的权限。",
         "share_link": "授予编辑共享链接功能的权限。",
         "bookmark": "授予编辑书签功能的权限。",
         "bookmark": "授予编辑书签功能的权限。",
         "attachment": "授予编辑附件功能的权限。",
         "attachment": "授予编辑附件功能的权限。",
-        "page_bulk_export": "授予编辑页面批量导出功能的权限。"
+        "page_bulk_export": "授予编辑页面批量导出功能的权限。",
+        "in_app_notification": "授予编辑应用内通知功能的权限。"
       }
       }
     }
     }
   }
   }

+ 4 - 4
apps/app/src/features/news/server/routes/news.ts

@@ -41,7 +41,7 @@ export const createNewsRouter = (crowi?: Crowi): express.Router => {
    */
    */
   router.get(
   router.get(
     '/list',
     '/list',
-    accessTokenParser([SCOPE.READ.USER_SETTINGS.IN_APP_NOTIFICATION], {
+    accessTokenParser([SCOPE.READ.FEATURES.IN_APP_NOTIFICATION], {
       acceptLegacy: true,
       acceptLegacy: true,
     }),
     }),
     loginRequiredStrictly,
     loginRequiredStrictly,
@@ -81,7 +81,7 @@ export const createNewsRouter = (crowi?: Crowi): express.Router => {
    */
    */
   router.get(
   router.get(
     '/unread-count',
     '/unread-count',
-    accessTokenParser([SCOPE.READ.USER_SETTINGS.IN_APP_NOTIFICATION], {
+    accessTokenParser([SCOPE.READ.FEATURES.IN_APP_NOTIFICATION], {
       acceptLegacy: true,
       acceptLegacy: true,
     }),
     }),
     loginRequiredStrictly,
     loginRequiredStrictly,
@@ -107,7 +107,7 @@ export const createNewsRouter = (crowi?: Crowi): express.Router => {
    */
    */
   router.post(
   router.post(
     '/mark-read',
     '/mark-read',
-    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.IN_APP_NOTIFICATION], {
+    accessTokenParser([SCOPE.WRITE.FEATURES.IN_APP_NOTIFICATION], {
       acceptLegacy: true,
       acceptLegacy: true,
     }),
     }),
     loginRequiredStrictly,
     loginRequiredStrictly,
@@ -142,7 +142,7 @@ export const createNewsRouter = (crowi?: Crowi): express.Router => {
    */
    */
   router.post(
   router.post(
     '/mark-all-read',
     '/mark-all-read',
-    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.IN_APP_NOTIFICATION], {
+    accessTokenParser([SCOPE.WRITE.FEATURES.IN_APP_NOTIFICATION], {
       acceptLegacy: true,
       acceptLegacy: true,
     }),
     }),
     loginRequiredStrictly,
     loginRequiredStrictly,

+ 4 - 4
apps/app/src/server/routes/apiv3/in-app-notification.ts

@@ -133,7 +133,7 @@ module.exports = (crowi: Crowi) => {
    */
    */
   router.get(
   router.get(
     '/list',
     '/list',
-    accessTokenParser([SCOPE.READ.USER_SETTINGS.IN_APP_NOTIFICATION], {
+    accessTokenParser([SCOPE.READ.FEATURES.IN_APP_NOTIFICATION], {
       acceptLegacy: true,
       acceptLegacy: true,
     }),
     }),
     loginRequiredStrictly,
     loginRequiredStrictly,
@@ -222,7 +222,7 @@ module.exports = (crowi: Crowi) => {
    */
    */
   router.get(
   router.get(
     '/status',
     '/status',
-    accessTokenParser([SCOPE.READ.USER_SETTINGS.IN_APP_NOTIFICATION], {
+    accessTokenParser([SCOPE.READ.FEATURES.IN_APP_NOTIFICATION], {
       acceptLegacy: true,
       acceptLegacy: true,
     }),
     }),
     loginRequiredStrictly,
     loginRequiredStrictly,
@@ -272,7 +272,7 @@ module.exports = (crowi: Crowi) => {
    */
    */
   router.post(
   router.post(
     '/open',
     '/open',
-    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.IN_APP_NOTIFICATION], {
+    accessTokenParser([SCOPE.WRITE.FEATURES.IN_APP_NOTIFICATION], {
       acceptLegacy: true,
       acceptLegacy: true,
     }),
     }),
     loginRequiredStrictly,
     loginRequiredStrictly,
@@ -309,7 +309,7 @@ module.exports = (crowi: Crowi) => {
    */
    */
   router.put(
   router.put(
     '/all-statuses-open',
     '/all-statuses-open',
-    accessTokenParser([SCOPE.WRITE.USER_SETTINGS.IN_APP_NOTIFICATION], {
+    accessTokenParser([SCOPE.WRITE.FEATURES.IN_APP_NOTIFICATION], {
       acceptLegacy: true,
       acceptLegacy: true,
     }),
     }),
     loginRequiredStrictly,
     loginRequiredStrictly,

+ 3 - 3
packages/core/src/interfaces/scope.spec.ts

@@ -63,9 +63,9 @@ describe('Scope type', () => {
     // Expected count based on the SCOPE_SEED structure:
     // Expected count based on the SCOPE_SEED structure:
     // Admin: 17 leaf scopes + 1 wildcard = 18
     // Admin: 17 leaf scopes + 1 wildcard = 18
     // User Settings: 6 leaf + 2 nested (api) + 2 wildcards = 10
     // User Settings: 6 leaf + 2 nested (api) + 2 wildcards = 10
-    // Features: 6 leaf scopes + 1 wildcard = 7
-    // Total per action: 35
-    // Total: 35 * 2 (read/write) = 70
+    // Features: 7 leaf scopes + 1 wildcard = 8
+    // Total per action: 36
+    // Total: 36 * 2 (read/write) = 72
     // But some wildcards are at category level, so actual count may vary
     // But some wildcards are at category level, so actual count may vary
 
 
     // Just ensure we have a reasonable number of scopes
     // Just ensure we have a reasonable number of scopes

+ 3 - 0
packages/core/src/interfaces/scope.ts

@@ -48,6 +48,7 @@ const SCOPE_SEED_USER = {
     bookmark: {},
     bookmark: {},
     attachment: {},
     attachment: {},
     page_bulk_export: {},
     page_bulk_export: {},
+    in_app_notification: {},
   },
   },
 } as const;
 } as const;
 
 
@@ -124,6 +125,7 @@ type ReadFeaturesScope =
   | 'read:features:bookmark'
   | 'read:features:bookmark'
   | 'read:features:attachment'
   | 'read:features:attachment'
   | 'read:features:page_bulk_export'
   | 'read:features:page_bulk_export'
+  | 'read:features:in_app_notification'
   | 'read:features:*';
   | 'read:features:*';
 
 
 // Write scopes - Admin
 // Write scopes - Admin
@@ -167,6 +169,7 @@ type WriteFeaturesScope =
   | 'write:features:bookmark'
   | 'write:features:bookmark'
   | 'write:features:attachment'
   | 'write:features:attachment'
   | 'write:features:page_bulk_export'
   | 'write:features:page_bulk_export'
+  | 'write:features:in_app_notification'
   | 'write:features:*';
   | 'write:features:*';
 
 
 // Combined Scope type - all valid scope strings
 // Combined Scope type - all valid scope strings