diff --git a/frontend/src/routes/admin/+page.svelte b/frontend/src/routes/admin/+page.svelte index 5c0f481c..bc58d719 100644 --- a/frontend/src/routes/admin/+page.svelte +++ b/frontend/src/routes/admin/+page.svelte @@ -2222,6 +2222,24 @@ {#if u.role === 'admin'}{/if} {u.role} + {#if u.is_external} + + + + {t('admin.external_user', 'external')} + + {/if} {#if isOidcUser(u)} @@ -3453,6 +3471,17 @@ text-transform: uppercase; } + /* External / grant-only account marker. Sibling of `.badge--user` + in the same cell so the two stack horizontally; the accent + colour reuses `--color-warning-*` because "external" is the + same "attention needed" family as "you". */ + .badge--external { + margin-left: var(--space-1); + background: var(--color-warning-bg); + color: var(--color-warning-text); + text-transform: uppercase; + } + /* Enabled/disabled feature flag indicator on the dashboard cards. */ .ds-flag { font-size: 1.125rem; diff --git a/frontend/static/locales/ar.json b/frontend/static/locales/ar.json index 6a14bcb3..ee84fb3d 100644 --- a/frontend/static/locales/ar.json +++ b/frontend/static/locales/ar.json @@ -869,7 +869,9 @@ "drive_error_name_required": "اسم قرص مطلوب.", "drive_error_owner_required": "اختر مستخدمًا أو مجموعة كمالك للقرص.", "create_drive": "إنشاء قرص مشترك", - "no_drives": "لا توجد أقراص بعد." + "no_drives": "لا توجد أقراص بعد.", + "external_user": "خارجي", + "external_user_hint": "حساب بالدعوة فقط (magic-link أو OCM). لا يمكن أن يكون مسؤولًا ولا يمتلك حصة تخزين." }, "profile": { "page_title": "الملف الشخصي", diff --git a/frontend/static/locales/de.json b/frontend/static/locales/de.json index b0ea9910..f3883823 100644 --- a/frontend/static/locales/de.json +++ b/frontend/static/locales/de.json @@ -869,7 +869,9 @@ "drive_error_name_required": "Laufwerk-Name ist erforderlich.", "drive_error_owner_required": "Wähle einen Benutzer oder eine Gruppe als Eigentümer des Laufwerks.", "create_drive": "Gemeinsames Laufwerk erstellen", - "no_drives": "Noch keine Laufwerke." + "no_drives": "Noch keine Laufwerke.", + "external_user": "extern", + "external_user_hint": "Nur-Einladung-Konto (Magic-Link oder OCM). Kann kein Administrator sein und hat keinen Speicherumfang." }, "profile": { "page_title": "Profil", diff --git a/frontend/static/locales/en.json b/frontend/static/locales/en.json index 162fd5db..e8abeb3c 100644 --- a/frontend/static/locales/en.json +++ b/frontend/static/locales/en.json @@ -1166,7 +1166,9 @@ "drive_error_name_required": "Drive name is required.", "drive_error_owner_required": "Pick a user or group as the drive owner.", "create_drive": "Create shared drive", - "no_drives": "No drives yet." + "no_drives": "No drives yet.", + "external_user": "external", + "external_user_hint": "Grant-only account (magic-link or OCM). Cannot be admin and has no storage envelope." }, "profile": { "page_title": "Profile", diff --git a/frontend/static/locales/es.json b/frontend/static/locales/es.json index b1632054..9c3a1015 100644 --- a/frontend/static/locales/es.json +++ b/frontend/static/locales/es.json @@ -884,7 +884,9 @@ "drive_error_name_required": "El nombre de la unidad es obligatorio.", "drive_error_owner_required": "Elige un usuario o un grupo como propietario de la unidad.", "create_drive": "Crear unidad compartida", - "no_drives": "Aún no hay unidades." + "no_drives": "Aún no hay unidades.", + "external_user": "externo", + "external_user_hint": "Cuenta solo con invitación (magic-link u OCM). No puede ser admin y no tiene cuota de almacenamiento." }, "profile": { "page_title": "Perfil", diff --git a/frontend/static/locales/fa.json b/frontend/static/locales/fa.json index e1a630ad..8f3fb0b9 100644 --- a/frontend/static/locales/fa.json +++ b/frontend/static/locales/fa.json @@ -852,7 +852,9 @@ "drive_error_name_required": "نام دیسک الزامی است.", "drive_error_owner_required": "یک کاربر یا گروه به عنوان مالک دیسک انتخاب کنید.", "create_drive": "ایجاد دیسک اشتراکی", - "no_drives": "هنوز دیسکی وجود ندارد." + "no_drives": "هنوز دیسکی وجود ندارد.", + "external_user": "خارجی", + "external_user_hint": "حساب فقط با دعوت (magic-link یا OCM). نمی‌تواند مدیر باشد و سهمیه ذخیره‌سازی ندارد." }, "profile": { "page_title": "پروفایل", diff --git a/frontend/static/locales/fr.json b/frontend/static/locales/fr.json index 5fb1ada0..73e1dee0 100644 --- a/frontend/static/locales/fr.json +++ b/frontend/static/locales/fr.json @@ -869,7 +869,9 @@ "drive_error_name_required": "Le nom du disque est requis.", "drive_error_owner_required": "Choisissez un utilisateur ou un groupe comme propriétaire du disque.", "create_drive": "Créer un disque partagé", - "no_drives": "Aucun disque pour le moment." + "no_drives": "Aucun disque pour le moment.", + "external_user": "externe", + "external_user_hint": "Compte à accès par invitation (magic-link ou OCM). Ne peut pas être admin et n’a pas de quota de stockage." }, "profile": { "page_title": "Profil", diff --git a/frontend/static/locales/hi.json b/frontend/static/locales/hi.json index e09542d8..98c09042 100644 --- a/frontend/static/locales/hi.json +++ b/frontend/static/locales/hi.json @@ -869,7 +869,9 @@ "drive_error_name_required": "ड्राइव का नाम आवश्यक है।", "drive_error_owner_required": "ड्राइव के स्वामी के रूप में एक उपयोगकर्ता या समूह चुनें।", "create_drive": "साझा ड्राइव बनाएँ", - "no_drives": "अभी तक कोई ड्राइव नहीं।" + "no_drives": "अभी तक कोई ड्राइव नहीं।", + "external_user": "बाहरी", + "external_user_hint": "केवल-आमंत्रण खाता (magic-link या OCM). व्यवस्थापक नहीं हो सकता और कोई भंडारण कोटा नहीं है।" }, "profile": { "page_title": "प्रोफ़ाइल", diff --git a/frontend/static/locales/it.json b/frontend/static/locales/it.json index ea5c3c80..3f172444 100644 --- a/frontend/static/locales/it.json +++ b/frontend/static/locales/it.json @@ -869,7 +869,9 @@ "drive_error_name_required": "Il nome dell'unità è obbligatorio.", "drive_error_owner_required": "Scegli un utente o un gruppo come proprietario dell'unità.", "create_drive": "Crea unità condivisa", - "no_drives": "Ancora nessuna unità." + "no_drives": "Ancora nessuna unità.", + "external_user": "esterno", + "external_user_hint": "Account solo su invito (magic-link o OCM). Non può essere amministratore e non ha un limite di archiviazione." }, "profile": { "page_title": "Profilo", diff --git a/frontend/static/locales/ja.json b/frontend/static/locales/ja.json index ea7516df..5b645539 100644 --- a/frontend/static/locales/ja.json +++ b/frontend/static/locales/ja.json @@ -869,7 +869,9 @@ "drive_error_name_required": "ドライブ名は必須です。", "drive_error_owner_required": "ドライブの所有者としてユーザーまたはグループを選択してください。", "create_drive": "共有ドライブを作成", - "no_drives": "ドライブはまだありません。" + "no_drives": "ドライブはまだありません。", + "external_user": "外部", + "external_user_hint": "招待専用アカウント(マジックリンクまたは OCM)。管理者にはなれず、ストレージ枠を持ちません。" }, "profile": { "page_title": "プロフィール", diff --git a/frontend/static/locales/ko.json b/frontend/static/locales/ko.json index 2cf9728f..3cc691a8 100644 --- a/frontend/static/locales/ko.json +++ b/frontend/static/locales/ko.json @@ -1129,7 +1129,9 @@ "drive_error_name_required": "드라이브 이름은 필수입니다.", "drive_error_owner_required": "드라이브 소유자로 사용자 또는 그룹을 선택하세요.", "create_drive": "공유 드라이브 만들기", - "no_drives": "아직 드라이브가 없습니다." + "no_drives": "아직 드라이브가 없습니다.", + "external_user": "외부", + "external_user_hint": "초대 전용 계정(매직 링크 또는 OCM). 관리자가 될 수 없으며 저장소 할당량이 없습니다." }, "profile": { "page_title": "프로필", diff --git a/frontend/static/locales/nl.json b/frontend/static/locales/nl.json index cc2de7c4..d5e1a463 100644 --- a/frontend/static/locales/nl.json +++ b/frontend/static/locales/nl.json @@ -869,7 +869,9 @@ "drive_error_name_required": "Schijfnaam is vereist.", "drive_error_owner_required": "Kies een gebruiker of groep als eigenaar van de schijf.", "create_drive": "Gedeelde schijf aanmaken", - "no_drives": "Nog geen schijven." + "no_drives": "Nog geen schijven.", + "external_user": "extern", + "external_user_hint": "Alleen-uitnodiging account (magic-link of OCM). Kan geen beheerder zijn en heeft geen opslagenveloppe." }, "profile": { "page_title": "Profiel", diff --git a/frontend/static/locales/pl.json b/frontend/static/locales/pl.json index f0cf4ce5..836194ec 100644 --- a/frontend/static/locales/pl.json +++ b/frontend/static/locales/pl.json @@ -869,7 +869,9 @@ "drive_error_name_required": "Nazwa dysku jest wymagana.", "drive_error_owner_required": "Wybierz użytkownika lub grupę jako właściciela dysku.", "create_drive": "Utwórz dysk współdzielony", - "no_drives": "Brak dysków." + "no_drives": "Brak dysków.", + "external_user": "zewnętrzny", + "external_user_hint": "Konto tylko z zaproszenia (magic-link lub OCM). Nie może być administratorem i nie ma limitu przestrzeni." }, "profile": { "page_title": "Profil", diff --git a/frontend/static/locales/pt.json b/frontend/static/locales/pt.json index 0601d0bb..9f7dfb8d 100644 --- a/frontend/static/locales/pt.json +++ b/frontend/static/locales/pt.json @@ -869,7 +869,9 @@ "drive_error_name_required": "O nome da unidade é obrigatório.", "drive_error_owner_required": "Escolha um utilizador ou grupo como proprietário da unidade.", "create_drive": "Criar unidade partilhada", - "no_drives": "Ainda não existem unidades." + "no_drives": "Ainda não existem unidades.", + "external_user": "externo", + "external_user_hint": "Conta apenas por convite (magic-link ou OCM). Não pode ser administrador e não tem quota de armazenamento." }, "profile": { "page_title": "Perfil", diff --git a/frontend/static/locales/ru.json b/frontend/static/locales/ru.json index 261130c7..e63bbbf0 100644 --- a/frontend/static/locales/ru.json +++ b/frontend/static/locales/ru.json @@ -869,7 +869,9 @@ "drive_error_name_required": "Имя диска обязательно.", "drive_error_owner_required": "Выберите пользователя или группу как владельца диска.", "create_drive": "Создать общий диск", - "no_drives": "Пока нет дисков." + "no_drives": "Пока нет дисков.", + "external_user": "внешний", + "external_user_hint": "Аккаунт только по приглашению (magic-link или OCM). Не может быть администратором и не имеет квоты хранилища." }, "profile": { "page_title": "Профиль", diff --git a/frontend/static/locales/zh-TW.json b/frontend/static/locales/zh-TW.json index 2293c7c0..7b1354b5 100644 --- a/frontend/static/locales/zh-TW.json +++ b/frontend/static/locales/zh-TW.json @@ -852,7 +852,9 @@ "drive_error_name_required": "雲端硬碟名稱為必填。", "drive_error_owner_required": "請選擇一位使用者或群組作為雲端硬碟擁有者。", "create_drive": "建立共用雲端硬碟", - "no_drives": "尚無雲端硬碟。" + "no_drives": "尚無雲端硬碟。", + "external_user": "外部", + "external_user_hint": "僅邀請帳戶(magic-link 或 OCM)。無法作為管理員,亦無儲存配額。" }, "profile": { "page_title": "個人資料", diff --git a/frontend/static/locales/zh.json b/frontend/static/locales/zh.json index 9e83032c..bcf7a13b 100644 --- a/frontend/static/locales/zh.json +++ b/frontend/static/locales/zh.json @@ -852,7 +852,9 @@ "drive_error_name_required": "云盘名称为必填项。", "drive_error_owner_required": "请选择用户或群组作为云盘所有者。", "create_drive": "创建共享云盘", - "no_drives": "暂无云盘。" + "no_drives": "暂无云盘。", + "external_user": "外部", + "external_user_hint": "仅邀请账户(magic-link 或 OCM)。不能作为管理员,也没有存储配额。" }, "profile": { "page_title": "个人资料", diff --git a/src/interfaces/api/handlers/admin_handler.rs b/src/interfaces/api/handlers/admin_handler.rs index c6ac3ebb..5e3bdfb2 100644 --- a/src/interfaces/api/handlers/admin_handler.rs +++ b/src/interfaces/api/handlers/admin_handler.rs @@ -754,9 +754,14 @@ pub async fn list_users( let limit = query.limit.unwrap_or(100).min(500); let offset = query.offset.unwrap_or(0); + // Admin surface must show *every* account for audit — grant-only + // magic-link / OCM recipients (is_external = true) included. The + // internal-only variant is used by system address book / sharee + // search, where surfacing externals would leak identities. See + // `auth_application_service::list_users` doc for the split. let users = auth .auth_application_service - .list_users(limit, offset) + .list_users_including_external(limit, offset) .await .map_err(|e| AppError::internal_error(format!("Failed to list users: {}", e)))?;