[settingsSync] use actionRequired if lacking authorization in CloudConfigServerCommunicator

GitOrigin-RevId: a47d1639ed6cec290b99543055f7ff98186a3925
This commit is contained in:
Sergey Pak
2025-04-08 23:46:40 +00:00
committed by intellij-monorepo-bot
parent 32efef3866
commit e8172ae615
6 changed files with 41 additions and 21 deletions
@@ -108,8 +108,10 @@ sync.notification.restart.message.list.entry.plugin.disable=Disable {0,choice,1#
sync.restart.notification.submessage.plugins={0} plugin(s): {1}\u2026
# {0} - IDE name, i.e. Android Studio, MPS, etc.
sync.restart.notification.action=Restart {0}
sync.status.enabled=Backup and Sync enabled for
sync.status.enabled=Backup and Sync is enabled
sync.status.will.enable=Backup and Sync will be enabled
sync.status.disabled=Backup and Sync disabled
sync.status.will.disable=Backup and Sync will be disabled
sync.status.action.required=Action required: {0}
sync.status.failed=Sync failed: {0}
sync.status.login.message=Login to enable Backup and Sync
@@ -5,6 +5,7 @@ import com.intellij.openapi.components.Service
import com.intellij.openapi.diagnostic.logger
import com.intellij.util.EventDispatcher
import org.jetbrains.annotations.Nls
import java.awt.Component
import java.util.*
@Service
@@ -53,7 +54,7 @@ class SettingsSyncStatusTracker {
eventDispatcher.multicaster.syncStatusChanged()
}
fun setActionRequired(message: @Nls String, actionTitle: @Nls String, action: suspend () -> Unit) {
fun setActionRequired(message: @Nls String, actionTitle: @Nls String, action: suspend (Component?) -> Unit) {
lastSyncTime = -1
state = SyncStatus.ActionRequired(message, actionTitle, action)
eventDispatcher.multicaster.syncStatusChanged()
@@ -93,8 +94,8 @@ class SettingsSyncStatusTracker {
*/
class ActionRequired(val message: @Nls String,
val actionTitle: @Nls String,
private val action: suspend() -> Unit): SyncStatus() {
suspend fun execute() = action()
private val action: suspend(Component?) -> Unit): SyncStatus() {
suspend fun execute(component: Component?) = action(component)
}
}
}
@@ -305,7 +305,7 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
if (SettingsSyncStatusTracker.getInstance().currentStatus is SettingsSyncStatusTracker.SyncStatus.ActionRequired) {
val actionRequired = SettingsSyncStatusTracker.getInstance().currentStatus as SettingsSyncStatusTracker.SyncStatus.ActionRequired
runWithModalProgressBlocking(ModalTaskOwner.component(configPanel), actionRequired.actionTitle) {
actionRequired.execute()
actionRequired.execute(syncConfigPanel)
}
return
}
@@ -328,7 +328,10 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
return@runWithModalProgressBlocking
}
if (checkServerState(syncPanelHolder, remoteCommunicator, provider.authService.crossSyncSupported())) {
triggerUpdateConfigurable()
withContext(Dispatchers.EDT) {
triggerUpdateConfigurable()
}
cellDropDownLink.comment?.text = message("sync.status.will.enable")
} else {
enableCheckbox.isSelected = false
}
@@ -338,6 +341,7 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
val syncDisableOption = showDisableSyncDialog()
if (syncDisableOption != DisableSyncType.DONT_DISABLE) {
disableSyncOption.set(syncDisableOption)
cellDropDownLink.comment?.text = message("sync.status.will.disable")
} else {
enableCheckbox.isSelected = true
}
@@ -589,7 +593,7 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
//statusLabel.icon = AllIcons.General.Error
}
is SettingsSyncStatusTracker.SyncStatus.ActionRequired -> {
actionRequiredAction = { currentStatus.execute() }
actionRequiredAction = { currentStatus.execute(syncConfigPanel) }
actionRequiredLabel.text = currentStatus.message
actionRequiredButton.text = currentStatus.actionTitle
//actionRequiredData = Pair(currentStatus.message, currentStatus.actionTitle)
@@ -609,6 +613,7 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
}
// triggers fake action, which causes SettingEditor to update and check if configurable was modified
// must be called on EDT
private fun triggerUpdateConfigurable() {
val dumbAwareAction = DumbAwareAction.create(Consumer { _: AnActionEvent? ->
// do nothing
@@ -1,6 +1,7 @@
action.settingsSync.troubleShoot.text=Backup and Sync Troubleshooting
login.title=Please Log in Via The Opened Browser\u2026
login.troubles.message=In case you have problems, try to <a>Log in manually</a>
action.settingsSync.authRequired=Authorization Required
troubleshooting.loading.info.progress.dialog.title=Loading information about Backup and Sync\u2026
troubleshooting.dialog.title=Backup and Sync Troubleshooting
@@ -4,10 +4,10 @@ import com.intellij.ide.plugins.PluginManagerCore.isRunningFromSources
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.util.JDOMUtil
import com.intellij.settingsSync.core.AbstractServerCommunicator
import com.intellij.settingsSync.core.SettingsSyncBundle
import com.intellij.settingsSync.core.SettingsSyncEventListener
import com.intellij.settingsSync.core.SettingsSyncEvents
import com.intellij.settingsSync.core.SettingsSyncLocalSettings
import com.intellij.settingsSync.core.SettingsSyncSettings
import com.intellij.settingsSync.core.SettingsSyncStatusTracker
import com.intellij.settingsSync.jba.auth.JBAAuthService
import com.intellij.util.io.HttpRequests
import com.jetbrains.cloudconfig.CloudConfigFileClientV2
@@ -95,9 +95,9 @@ internal open class CloudConfigServerCommunicator(private val serverUrl: String?
}
else if (e is UnauthorizedException) {
_currentIdTokenVar?.also {
jbaAuthService.invalidateJBA(it)
LOG.warn("Got \"Unauthorized\" from Settings Sync server. Settings Sync will be disabled. Please login to JBA again")
SettingsSyncSettings.getInstance().syncEnabled = false
setAuthActionRequired()
jbaAuthService.invalidateJBA(it)
}
}
else {
@@ -158,20 +158,30 @@ internal open class CloudConfigServerCommunicator(private val serverUrl: String?
val idToken = jbaAuthService.idToken
_currentIdTokenVar = idToken
if (idToken == null) {
if (System.getProperty("settings.sync.allow.user.without.token") == "true")
return null
else
if (jbaAuthService.getAccountInfoService()?.userData != null) {
SettingsSyncSettings.getInstance().syncEnabled = false
SettingsSyncLocalSettings.getInstance().userId = null
SettingsSyncLocalSettings.getInstance().providerCode = null
}
if (jbaAuthService.getAccountInfoService()?.userData != null) {
setAuthActionRequired()
}
return null
} else {
configuration.auth(JbaJwtTokenAuthProvider(idToken))
}
return configuration
}
private fun setAuthActionRequired() {
if (SettingsSyncStatusTracker.getInstance().currentStatus is SettingsSyncStatusTracker.SyncStatus.ActionRequired)
return
SettingsSyncStatusTracker.getInstance().setActionRequired(
SettingsSyncJbaBundle.message("action.settingsSync.authRequired"),
SettingsSyncBundle.message("config.button.login")) {
val userData = jbaAuthService.login(it)
if (userData != null) {
SettingsSyncStatusTracker.getInstance().clearActionRequired()
SettingsSyncStatusTracker.getInstance().updateOnSuccess()
}
}
}
companion object {
private const val URL_PROVIDER = "https://www.jetbrains.com/config/IdeaCloudConfig.xml"
private const val DEFAULT_PRODUCTION_URL = "https://cloudconfig.jetbrains.com/cloudconfig"
@@ -4,6 +4,7 @@ import com.intellij.idea.TestFor
import com.intellij.openapi.application.ApplicationManager
import com.intellij.settingsSync.core.SettingsSyncMain
import com.intellij.settingsSync.core.SettingsSyncSettings
import com.intellij.settingsSync.core.SettingsSyncStatusTracker
import com.intellij.settingsSync.core.auth.SettingsSyncAuthService
import com.intellij.settingsSync.jba.CloudConfigServerCommunicator
import com.intellij.settingsSync.jba.CloudConfigVersionContext
@@ -89,7 +90,7 @@ internal class SettingsSyncAuthTest : BasePlatformTestCase() {
@Test
@TestFor(issues = ["IDEA-343073"])
fun `disable setting sync logged out on invalid idToken`() {
fun `setting sync set action required on invalid idToken`() {
SettingsSyncSettings.getInstance().syncEnabled = true
assertTrue(SettingsSyncSettings.getInstance().syncEnabled)
@@ -120,7 +121,7 @@ internal class SettingsSyncAuthTest : BasePlatformTestCase() {
communicator.checkServerState()
//assertFalse(authServiceSpy.isLoggedIn())
assertFalse(SettingsSyncSettings.getInstance().syncEnabled)
assertTrue(SettingsSyncStatusTracker.getInstance().currentStatus is SettingsSyncStatusTracker.SyncStatus.ActionRequired)
}
@Test