Repository navigation
Support users in multiple NDI Cloud organizations - #336
Merged
Merged
Conversation
Port of VH-Lab/NDI-matlab#1037. A user has one token but may belong to several organizations, so login no longer keeps only the first. - Login caches the user's whole organization list (id, name, canUploadDataset) as JSON in NDI_CLOUD_ORGANIZATIONS; logout clears it. New ndi.cloud.internal.normalizeOrganizations / setOrganizations / getOrganizations / chooseOrganization / userIsAdmin and ndi.cloud.ui.dialog.organizationLabels / selectOrganization. - chooseOrganization: a named organization, else the only qualifying one, else ask (on a terminal, or through a supplied chooser), else CloudOrganizationError listing them by name and id. RequireUpload honours canUploadDataset, and lets administrators upload anywhere, as the server does. - CloudConfig.org_id and NDI_CLOUD_ORGANIZATION_ID are gone; getActiveToken returns the token only; authenticate's second output is deprecated (the only organization, else ""). - createDataset / uploadDataset take organization_name / organization_id; listDatasets() with no organization lists every organization's datasets, tagged with organizationId/organizationName. - File uploads go to the organization that owns the dataset (read from its record, as MATLAB's GetFileUploadURL does), not the login's first. - The navigator lists cloud datasets across organizations and asks which organization on "Upload to Cloud". - Bridge entries synced to NDI-matlab 293ec411 / c24d338d / 9a3c972d; resolveOrganizationId retired; new entries for the +internal helpers. - Tests: offline test_cloud_organizations, live tests pass an explicit organization (tests/_cloud_organizations.testOrganizationID), and a guard that fails if a test creates a dataset without naming one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012b2n4N1dokzz1vXoRtdBQK
The User 2 Cloud API jobs failed at setup of test_cloud_file_series_round_trip:
that account may upload to none of its organizations and is not an
administrator, so testOrganizationID raised. Before, the same account got
HTTP 400 from createDataset and the fixture skipped ("cannot create cloud
dataset for this test"). Resolve the organization first and skip with the
same message.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012b2n4N1dokzz1vXoRtdBQK
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Port of VH-Lab/NDI-matlab#1037 (merged). An NDI Cloud user has one token but may belong to several organizations. Python kept only the first one (
CloudConfig.org_id/NDI_CLOUD_ORGANIZATION_ID, with a "selection is not yet supported" warning) and used it everywhere — including as the destination of file uploads for datasets that belong to a different organization.Organization list cached at login
ndi.cloud.auth.logincaches the user's whole organization list (id,name,canUploadDataset) as JSON inNDI_CLOUD_ORGANIZATIONS— the same variable NDI-matlab uses.logoutclears it (and any leftoverNDI_CLOUD_ORGANIZATION_ID).ndi/cloud/internal.py:normalizeOrganizations,setOrganizations,getOrganizations(cache, elseusers.me;refresh=True),chooseOrganization,userIsAdmin.ndi/cloud/ui/dialog.py:organizationLabels,selectOrganization(both wereporting_deferred).Choosing an organization
chooseOrganization: a namedorganization_name/organization_id, else the only qualifying organization, else ask, elseCloudOrganizationError(carrying MATLAB's identifier, e.g.NDI:Cloud:OrganizationRequired) that lists the organizations by name and id.require_uploadhonourscanUploadDatasetand, as the server does, lets administrators upload to any of their organizations. MATLAB asks in a desktop dialog; Python asks on the console when stdin is a terminal (numbered from 1), or through achoosercallable — the Qt navigator passes its list dialog.Datasets and uploads
createDatasetanduploadDatasettakeorganization_name/organization_id; a new dataset's organization comes fromchooseOrganization(require_upload=True).listDatasets()with no organization lists every page of every organization, tagging each dataset withorganizationId/organizationName(NDI Cloud only lists per organization). With an organization it is unchanged.listAllDatasets()follows.uploadFilesForDatasetDocuments,zipForUpload,uploadSingleFile, sync) now use the organization that owns the dataset, read from its record as MATLAB'sGetFileUploadURLdoes, instead of the login's first organization.[Org Name]when there is more than one; "Upload to Cloud" asks which organization.Breaking changes
CloudConfig.org_idandNDI_CLOUD_ORGANIZATION_IDare removed.ndi.cloud.auth.getActiveTokenreturns the token only.authenticate's second output is deprecated (as in MATLAB): the user's only organization, or""when there are several. Nothing in the repo reads it any more.Bridge
Synced to NDI-matlab
293ec411,c24d338d(admin rule) and9a3c972d(LoginDialog), all on NDI-matlabmainvia the merge:chooseOrganization,getOrganizations,setOrganizations,normalizeOrganizations,userIsAdmin.selectOrganization,organizationLabels. Retired:resolveOrganizationId(deleted in MATLAB).uploadDataset,createDataset,listDatasets,getActiveToken,authenticate.testLogin,uilogin,LoginDialog,cloudPane, pluslogout,selectCloudDataset,uploadFilesForDatasetDocuments,datasetsPane. The Python-only_resolve_org_idhelper and its entry are gone.Tests
tests/test_cloud_organizations.py(26 tests): normalization, cache, everychooseOrganizationbranch, the chooser and console prompt, labels, login/logout caching, dataset-organization lookup.tests/_cloud_organizations.testOrganizationID(first uploadable organization; any, for an administrator) instead ofcloud_config.org_id.tests/test_cloud_tests_name_organization.py(mirrors NDI-matlab'sCloudTestsNameOrganizationTest): fails if a test callscreateDataset/uploadDataset/newDatasetwithout naming an organization, which CI's single-organization account could never catch.config.org_id.Test plan
black --check src/ tests/,ruff check src/ tests/pytest tests/locally: 6043 passed, 609 skipped (live cloud tests skip without credentials)test_matlab_bridge_*, strict) against a full-history NDI-matlab checkout: 196 passedndi.cloud.internal.getOrganizations()lists all with names;uploadDatasetasks on a terminal and acceptsorganization_nameGenerated by Claude Code