Skip to content

fix: resolve tenant-specific URLs via drive meta API#932

Closed
KhanCold wants to merge 8 commits into
larksuite:mainfrom
KhanCold:fix/tenant-specific-urls
Closed

fix: resolve tenant-specific URLs via drive meta API#932
KhanCold wants to merge 8 commits into
larksuite:mainfrom
KhanCold:fix/tenant-specific-urls

Conversation

@KhanCold

@KhanCold KhanCold commented May 18, 2026

Copy link
Copy Markdown
Contributor

Problem

Several CLI shortcuts that create resources (drive +upload, drive +import, docs +create, markdown +create, wiki +node-create) use BuildResourceURL to generate user-facing URLs. BuildResourceURL hard-codes www.feishu.cn and www.larksuite.com as hosts. For tenants with private deployments or custom vanity domains, these URLs do not redirect correctly, leaving users with broken links.

Issues: #810, #925

Solution

Introduce FetchTenantResourceURL in shortcuts/common/tenant_url.go. This helper:

  1. Queries the drive meta batch_query API (with_url=true) to obtain the tenant-specific URL for the newly created resource.
  2. Falls back to BuildResourceURL when the API is unavailable, returns no URL, or the resource kind has no drive meta mapping.

This mirrors the existing pattern already used by slides +create (which calls batch_query directly) and is consistent with sheets +create / drive +create-folder (which read the url field from the create API response).

Changes

  • New file: shortcuts/common/tenant_url.goFetchTenantResourceURL + kindToDocType
  • New file: shortcuts/common/tenant_url_test.go — 7 unit tests covering meta URL resolution, fallback, empty token, unknown kind, and whitespace trimming
  • Modified: Replaced BuildResourceURL with FetchTenantResourceURL in:
    • shortcuts/drive/drive_upload.go
    • shortcuts/drive/drive_import.go
    • shortcuts/doc/docs_create.go
    • shortcuts/doc/docs_create_v2.go
    • shortcuts/markdown/markdown_create.go
    • shortcuts/wiki/wiki_node_create.go

Testing

  • go test ./shortcuts/common/ -run TestFetchTenantResourceURL — PASS (7/7)
  • go test ./shortcuts/wiki/ — PASS
  • go test ./shortcuts/markdown/ — PASS
  • go test ./shortcuts/doc/ — PASS
  • go test ./shortcuts/slides/ — PASS
  • go test ./shortcuts/sheets/ — PASS
  • go vet ./shortcuts/common/ ./shortcuts/drive/ ./shortcuts/wiki/ ./shortcuts/markdown/ ./shortcuts/doc/ ./shortcuts/slides/ ./shortcuts/sheets/ — clean
  • gofmt -l on all modified files — clean

Backward Compatibility

Public-cloud tenants continue to receive the same brand-standard URLs because BuildResourceURL is still the fallback when batch_query does not return a tenant-specific URL. No breaking changes to CLI flags or output shape.

Summary by CodeRabbit

  • Refactor

    • Enhanced resource URL resolution to use tenant-specific API lookups for documents, spreadsheets, files, wikis, and other content types, improving accuracy of resource addresses across the system.
  • Tests

    • Added comprehensive test coverage for URL resolution logic, including API response handling, fallback scenarios, and edge cases.

Review Change Stack

KhanCold added 8 commits May 18, 2026 08:35
…ack to brand-standard hosts

Replace direct BuildResourceURL calls with FetchTenantResourceURL in all
shortcuts that create resources and previously emitted hard-coded
www.feishu.cn / www.larksuite.com links:

- drive +upload
- drive +import
- docs +create (v1 fallback)
- docs +create (v2 fallback)
- markdown +create
- wiki +node-create

FetchTenantResourceURL queries the drive meta batch_query API with
with_url=true to obtain the tenant's actual vanity domain (e.g.
example.feishu.cn). This fixes broken links for private-deployment and
custom-domain tenants where the generic hosts do not redirect correctly.

If the meta lookup fails or returns no URL, the function falls back to
BuildResourceURL, preserving existing behavior for public-cloud tenants.

Closes #810, closes #925
…ack to brand-standard hosts

Replace direct BuildResourceURL calls with FetchTenantResourceURL in all shortcuts that create resources and previously emitted hard-coded www.feishu.cn / www.larksuite.com links:

- drive +upload
- drive +import
- docs +create (v1 fallback)
- docs +create (v2 fallback)
- markdown +create
- wiki +node-create

FetchTenantResourceURL queries the drive meta batch_query API with with_url=true to obtain the tenant actual vanity domain (e.g. example.feishu.cn). This fixes broken links for private-deployment and custom-domain tenants where the generic hosts do not redirect correctly.

If the meta lookup fails or returns no URL, the function falls back to BuildResourceURL, preserving existing behavior for public-cloud tenants.

Closes #810, closes #925
…ack to brand-standard hosts

Replace direct BuildResourceURL calls with FetchTenantResourceURL in all shortcuts that create resources and previously emitted hard-coded www.feishu.cn / www.larksuite.com links:

- drive +upload
- drive +import
- docs +create (v1 fallback)
- docs +create (v2 fallback)
- markdown +create
- wiki +node-create

FetchTenantResourceURL queries the drive meta batch_query API with with_url=true to obtain the tenant actual vanity domain (e.g. example.feishu.cn). This fixes broken links for private-deployment and custom-domain tenants where the generic hosts do not redirect correctly.

If the meta lookup fails or returns no URL, the function falls back to BuildResourceURL, preserving existing behavior for public-cloud tenants.

Closes #810, closes #925
…ack to brand-standard hosts

Replace direct BuildResourceURL calls with FetchTenantResourceURL in all shortcuts that create resources and previously emitted hard-coded www.feishu.cn / www.larksuite.com links:

- drive +upload
- drive +import
- docs +create (v1 fallback)
- docs +create (v2 fallback)
- markdown +create
- wiki +node-create

FetchTenantResourceURL queries the drive meta batch_query API with with_url=true to obtain the tenant actual vanity domain (e.g. example.feishu.cn). This fixes broken links for private-deployment and custom-domain tenants where the generic hosts do not redirect correctly.

If the meta lookup fails or returns no URL, the function falls back to BuildResourceURL, preserving existing behavior for public-cloud tenants.

Closes #810, closes #925
…ack to brand-standard hosts

Replace direct BuildResourceURL calls with FetchTenantResourceURL in all shortcuts that create resources and previously emitted hard-coded www.feishu.cn / www.larksuite.com links:

- drive +upload
- drive +import
- docs +create (v1 fallback)
- docs +create (v2 fallback)
- markdown +create
- wiki +node-create

FetchTenantResourceURL queries the drive meta batch_query API with with_url=true to obtain the tenant actual vanity domain (e.g. example.feishu.cn). This fixes broken links for private-deployment and custom-domain tenants where the generic hosts do not redirect correctly.

If the meta lookup fails or returns no URL, the function falls back to BuildResourceURL, preserving existing behavior for public-cloud tenants.

Closes #810, closes #925
…ack to brand-standard hosts

Replace direct BuildResourceURL calls with FetchTenantResourceURL in all shortcuts that create resources and previously emitted hard-coded www.feishu.cn / www.larksuite.com links:

- drive +upload
- drive +import
- docs +create (v1 fallback)
- docs +create (v2 fallback)
- markdown +create
- wiki +node-create

FetchTenantResourceURL queries the drive meta batch_query API with with_url=true to obtain the tenant actual vanity domain (e.g. example.feishu.cn). This fixes broken links for private-deployment and custom-domain tenants where the generic hosts do not redirect correctly.

If the meta lookup fails or returns no URL, the function falls back to BuildResourceURL, preserving existing behavior for public-cloud tenants.

Closes #810, closes #925
…ack to brand-standard hosts

Replace direct BuildResourceURL calls with FetchTenantResourceURL in all shortcuts that create resources and previously emitted hard-coded www.feishu.cn / www.larksuite.com links:

- drive +upload
- drive +import
- docs +create (v1 fallback)
- docs +create (v2 fallback)
- markdown +create
- wiki +node-create

FetchTenantResourceURL queries the drive meta batch_query API with with_url=true to obtain the tenant actual vanity domain (e.g. example.feishu.cn). This fixes broken links for private-deployment and custom-domain tenants where the generic hosts do not redirect correctly.

If the meta lookup fails or returns no URL, the function falls back to BuildResourceURL, preserving existing behavior for public-cloud tenants.

Closes #810, closes #925
Copilot AI review requested due to automatic review settings May 18, 2026 00:38
@CLAassistant

CLAassistant commented May 18, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR adds tenant-aware resource URL resolution via a new FetchTenantResourceURL helper that queries the drive meta batch API, then applies it uniformly across document, drive, markdown, and wiki resource creation to replace the previous brand-based URL construction.

Changes

Tenant-aware URL Resolution

Layer / File(s) Summary
Tenant URL resolution utility
shortcuts/common/tenant_url.go
Introduces FetchTenantResourceURL, which resolves resource URLs by calling the drive meta batch_query API with with_url=true, trimming/validating input tokens, mapping kind to doc_type, extracting tenant-specific URLs from the response, and falling back to BuildResourceURL when the meta lookup fails or returns no usable URL.
Tenant URL utility tests and helpers
shortcuts/common/tenant_url_test.go
Comprehensive test coverage for FetchTenantResourceURL and kindToDocType: successful meta URL resolution, fallback scenarios (empty metas, API failure, whitespace URLs), edge cases (empty token, unknown kind), mapping validation for all supported kinds, and a test runtime helper for API mocking.
Document creation URL resolution
shortcuts/doc/docs_create.go, shortcuts/doc/docs_create_v2.go
Document v1 and v2 creation flows now use FetchTenantResourceURL to resolve doc_url when the API response omits it but provides a document ID, replacing brand-based BuildResourceURL.
Drive resource URL resolution
shortcuts/drive/drive_import.go, shortcuts/drive/drive_upload.go
Drive import and file upload flows now use FetchTenantResourceURL instead of BuildResourceURL to emit resource URLs, enabling tenant-scoped URL lookups for imported documents and uploaded files.
Markdown and wiki resource URL resolution
shortcuts/markdown/markdown_create.go, shortcuts/wiki/wiki_node_create.go
Markdown file creation and wiki node creation now use FetchTenantResourceURL to emit resource URLs, aligning with tenant-aware URL resolution across all resource types.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • larksuite/cli#680: The main PR refactors the existing "backfill omitted url" logic to use the new FetchTenantResourceURL helper, which in turn falls back to common.BuildResourceURL, making the changes directly build on and replace the BuildResourceURL-based behavior introduced in PR #680.

Suggested labels

size/L, domain/ccm

Suggested reviewers

  • fangshuyu-768

Poem

🐰 A curious rabbit hops through the tenant's domain,
Fetching URLs with batch queries—no more brand-based refrain!
From doc to drive, each shortcut now knows its place,
Tenant-aware lookups put a smile on every face.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: introducing a new approach to resolve tenant-specific URLs via the drive meta API instead of hard-coded hosts.
Description check ✅ Passed The description comprehensively covers the problem, solution, detailed changes, testing evidence, and backward compatibility assurances, matching the required template structure.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added domain/ccm PR touches the ccm domain size/L Large or sensitive change across domains or core paths labels May 18, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@shortcuts/common/tenant_url_test.go`:
- Around line 204-205: The test helper is ignoring the error returned from
f.Config(), so update the setup to handle the error explicitly: call f.Config()
and check the returned error, e.g. if err != nil { t.Fatalf(...) } (or return
the error up) before passing cfg into TestNewRuntimeContextForAPI; locate the
call to f.Config() and the return into TestNewRuntimeContextForAPI in the test
helper and add proper error handling for the cfg, preserving use of
TestNewRuntimeContextForAPI(context.Background(), cmd, cfg, f, core.AsBot).

In `@shortcuts/common/tenant_url.go`:
- Line 59: Normalize the incoming kind before using it for fallback URL
building: trim whitespace and normalize case (e.g., strings.TrimSpace +
strings.ToLower) on the kind variable and use that normalized value when calling
BuildResourceURL and any meta lookup via kindToDocType so inputs like " DOCX "
produce a correct fallback URL; update the call site that currently does
BuildResourceURL(runtime.Config.Brand, kind, token) to pass the normalizedKind
instead.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fba107b3-a85c-41c7-a7d7-fe4ec98c4274

📥 Commits

Reviewing files that changed from the base of the PR and between 898e0ee and 39d9177.

📒 Files selected for processing (8)
  • shortcuts/common/tenant_url.go
  • shortcuts/common/tenant_url_test.go
  • shortcuts/doc/docs_create.go
  • shortcuts/doc/docs_create_v2.go
  • shortcuts/drive/drive_import.go
  • shortcuts/drive/drive_upload.go
  • shortcuts/markdown/markdown_create.go
  • shortcuts/wiki/wiki_node_create.go

Comment on lines +204 to +205
cfg, _ := f.Config()
return TestNewRuntimeContextForAPI(context.Background(), cmd, cfg, f, core.AsBot)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Handle f.Config() errors explicitly in test helper.

Ignoring the error can hide setup failures and make test breakage harder to diagnose.

Suggested fix
 func newTestRuntimeForTenantURL(t *testing.T, f *cmdutil.Factory) *RuntimeContext {
 	t.Helper()
 	cmd := &cobra.Command{Use: "test"}
 	cmd.SetContext(context.Background())
-	cfg, _ := f.Config()
+	cfg, err := f.Config()
+	if err != nil {
+		t.Fatalf("f.Config() failed: %v", err)
+	}
 	return TestNewRuntimeContextForAPI(context.Background(), cmd, cfg, f, core.AsBot)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cfg, _ := f.Config()
return TestNewRuntimeContextForAPI(context.Background(), cmd, cfg, f, core.AsBot)
func newTestRuntimeForTenantURL(t *testing.T, f *cmdutil.Factory) *RuntimeContext {
t.Helper()
cmd := &cobra.Command{Use: "test"}
cmd.SetContext(context.Background())
cfg, err := f.Config()
if err != nil {
t.Fatalf("f.Config() failed: %v", err)
}
return TestNewRuntimeContextForAPI(context.Background(), cmd, cfg, f, core.AsBot)
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shortcuts/common/tenant_url_test.go` around lines 204 - 205, The test helper
is ignoring the error returned from f.Config(), so update the setup to handle
the error explicitly: call f.Config() and check the returned error, e.g. if err
!= nil { t.Fatalf(...) } (or return the error up) before passing cfg into
TestNewRuntimeContextForAPI; locate the call to f.Config() and the return into
TestNewRuntimeContextForAPI in the test helper and add proper error handling for
the cfg, preserving use of TestNewRuntimeContextForAPI(context.Background(),
cmd, cfg, f, core.AsBot).

}
}

return BuildResourceURL(runtime.Config.Brand, kind, token)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Normalize kind before fallback URL building.

kindToDocType accepts trimmed/case-insensitive kinds, but fallback uses raw kind. If meta lookup fails, valid inputs like " DOCX " can still produce a broken/empty fallback URL.

Suggested fix
 func FetchTenantResourceURL(runtime *RuntimeContext, kind, token string) string {
 	token = strings.TrimSpace(token)
+	normalizedKind := strings.ToLower(strings.TrimSpace(kind))
 	if token == "" {
 		return ""
 	}
 
-	docType := kindToDocType(kind)
+	docType := kindToDocType(normalizedKind)
 	if docType != "" {
 		if metaData, err := runtime.CallAPI(
 			"POST",
 			"/open-apis/drive/v1/metas/batch_query",
@@
-	return BuildResourceURL(runtime.Config.Brand, kind, token)
+	return BuildResourceURL(runtime.Config.Brand, normalizedKind, token)
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shortcuts/common/tenant_url.go` at line 59, Normalize the incoming kind
before using it for fallback URL building: trim whitespace and normalize case
(e.g., strings.TrimSpace + strings.ToLower) on the kind variable and use that
normalized value when calling BuildResourceURL and any meta lookup via
kindToDocType so inputs like " DOCX " produce a correct fallback URL; update the
call site that currently does BuildResourceURL(runtime.Config.Brand, kind,
token) to pass the normalizedKind instead.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes broken user-facing URLs for newly created Drive/Docs/Wiki resources in tenants that use private deployments or custom vanity domains by resolving URLs via the Drive meta batch_query API (with with_url=true) and falling back to the existing brand-standard URL builder when needed.

Changes:

  • Added FetchTenantResourceURL helper that attempts to fetch a tenant-specific URL via /open-apis/drive/v1/metas/batch_query, with fallback to BuildResourceURL.
  • Added unit tests covering meta URL resolution, fallback behavior, empty token, unknown kind, and whitespace trimming.
  • Updated several shortcuts to use FetchTenantResourceURL instead of hard-coded-host BuildResourceURL when emitting URLs.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
shortcuts/common/tenant_url.go Adds tenant-aware URL resolution via Drive meta API with fallback to brand-standard URLs.
shortcuts/common/tenant_url_test.go Adds unit tests for the new tenant URL resolution behavior.
shortcuts/wiki/wiki_node_create.go Uses tenant-aware URL resolution for newly created wiki nodes.
shortcuts/markdown/markdown_create.go Uses tenant-aware URL resolution for created markdown files.
shortcuts/drive/drive_upload.go Uses tenant-aware URL resolution for uploaded files (when applicable).
shortcuts/drive/drive_import.go Uses tenant-aware URL resolution for imported document results when URL is missing.
shortcuts/doc/docs_create.go Uses tenant-aware URL resolution for v1 docs-create URL fallback.
shortcuts/doc/docs_create_v2.go Uses tenant-aware URL resolution for v2 docs-create URL fallback.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +66 to +69
switch strings.ToLower(strings.TrimSpace(kind)) {
case "docx", "doc":
return "docx"
case "sheet":
Comment on lines +20 to +25
// The kind parameter must be a value BuildResourceURL recognizes (docx, sheet,
// wiki, file, folder, slides, bitable, mindnote). doc_type for the meta API
// is derived from kind automatically.
//
// Returns "" only when both the meta lookup and the brand fallback fail
// (typically because token is empty).
@KhanCold KhanCold closed this May 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain/ccm PR touches the ccm domain size/L Large or sensitive change across domains or core paths

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants