diff --git a/keepercommander/commands/record.py b/keepercommander/commands/record.py index 3f58bb0f8..bc745ebed 100644 --- a/keepercommander/commands/record.py +++ b/keepercommander/commands/record.py @@ -290,6 +290,21 @@ class RecordGetUidCommand(Command): def get_parser(self): return get_info_parser + @staticmethod + def _is_classic_shared_folder_owner(user, owner_username, owner_account_uid): + """Return True if *user* matches the classic shared folder owner from sync-down.""" + if not user: + return False + if owner_username: + username = user.get('username') or '' + if username and username.lower() == owner_username.lower(): + return True + if owner_account_uid: + account_uid = user.get('account_uid') or '' + if account_uid and account_uid == owner_account_uid: + return True + return False + @staticmethod def _build_folder_json(params, f): folder_type = 'nested_share_folder' if f.type == BaseFolderNode.NestedShareFolderType else 'classic_folder' @@ -365,6 +380,9 @@ def execute(self, params, **kwargs): if api.is_shared_folder(params, uid): admins = api.get_share_admins_for_shared_folder(params, uid) sf = api.get_shared_folder(params, uid) + cached_sf = params.shared_folder_cache.get(uid) or {} + owner_username = cached_sf.get('owner_username') + owner_account_uid = cached_sf.get('owner_account_uid') if fmt == 'json': path = get_folder_path(params, sf.shared_folder_uid, delimiter=os.sep) if sf.shared_folder_uid else '' sf_node = params.folder_cache.get(sf.shared_folder_uid) if sf.shared_folder_uid else None @@ -405,6 +423,8 @@ def _format_expiration(expiration_value): sfo['users'] = [{ 'username': u['username'], 'user_id': u.get('account_uid'), + 'owner': RecordGetUidCommand._is_classic_shared_folder_owner( + u, owner_username, owner_account_uid), 'manage_records': u['manage_records'], 'manage_users': u['manage_users'], 'expiration': _format_expiration(u.get('expiration')) diff --git a/unit-tests/test_command_record.py b/unit-tests/test_command_record.py index 03de045fc..e2f6b1684 100644 --- a/unit-tests/test_command_record.py +++ b/unit-tests/test_command_record.py @@ -304,6 +304,27 @@ def test_get_shared_folder_uid(self): cmd.execute(params, uid=shared_folder_uid) cmd.execute(params, format='json', uid=shared_folder_uid) + def test_get_shared_folder_json_includes_owner_flag(self): + params = get_synced_params() + cmd = record.RecordGetUidCommand() + shared_folder_uid = next(iter(params.shared_folder_cache)) + cached_sf = params.shared_folder_cache[shared_folder_uid] + owner_account_uid = cached_sf['owner_account_uid'] + + captured = [] + with mock.patch('builtins.print', side_effect=captured.append), \ + mock.patch('keepercommander.api.get_share_admins_for_shared_folder', return_value=[]): + cmd.execute(params, format='json', uid=shared_folder_uid) + + payload = json.loads(captured[-1]) + self.assertEqual(payload['type'], 'classic_folder') + self.assertIn('users', payload) + self.assertTrue(payload['users']) + owners = [u for u in payload['users'] if u.get('owner')] + self.assertEqual(len(owners), 1) + self.assertEqual(owners[0]['user_id'], owner_account_uid) + self.assertTrue(all('owner' in u for u in payload['users'])) + def test_get_user_folder_json_consistent_by_name_and_uid(self): params = get_synced_params() cmd = record.RecordGetUidCommand()