package drive import ( "context" "encoding/json" "fmt" "strings" "github.com/ultisuite/ulti-backend/internal/driveroot" "github.com/ultisuite/ulti-backend/internal/nextcloud" ) func mountOAuthAccessToken(configEnc []byte) string { if len(configEnc) == 0 { return "" } var cfg map[string]any if err := json.Unmarshal(configEnc, &cfg); err != nil { return "" } if raw, ok := cfg["token"].(string); ok { return nextcloud.ParseOAuthAccessToken(raw) } return "" } // ResolveMountExternalURL returns the provider web URL for a file on an external mount. func (s *Service) ResolveMountExternalURL(ctx context.Context, ncUserID, mountID, platformUserID, logicalPath string) (string, error) { store := s.ensureStore() if store == nil { return "", fmt.Errorf("store not configured") } mount, err := store.GetMount(ctx, mountID) if err != nil { return "", err } if mount.OwnerUserID == nil || *mount.OwnerUserID != platformUserID { return "", ErrForbidden } logicalPath = nextcloud.NormalizeClientPath(logicalPath) if logicalPath == "/" { return "", ErrInvalid } file, err := s.StatFileAtRoot(ctx, ncUserID, driveroot.Mount(mountID, logicalPath)) if err != nil { return "", err } if file.ExternalURL != "" { return file.ExternalURL, nil } if !file.OpenExternally { return "", ErrInvalid } configEnc, err := store.GetMountConfig(ctx, mountID) if err != nil { return "", err } accessToken := mountOAuthAccessToken(configEnc) if accessToken == "" { return "", fmt.Errorf("mount oauth token not available") } resolver := &nextcloud.MountCloudResolver{} backend := driveroot.NormalizeMountBackend(mount.BackendType) switch backend { case "google": if id := providerIDFromETag(file.ETag); id != "" { link, err := resolver.GoogleDriveWebViewLink(ctx, accessToken, id) if err == nil && link != "" { return link, nil } } return resolver.ResolveGoogleDrivePath(ctx, accessToken, logicalPath) case "microsoft": return resolver.ResolveMicrosoftDrivePath(ctx, accessToken, logicalPath) default: return "", ErrInvalid } } func providerIDFromETag(etag string) string { id := strings.Trim(strings.TrimSpace(etag), "\"") if id == "" { return "" } for _, r := range id { if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '_' || r == '-' { continue } return "" } if len(id) < 10 { return "" } return id }