diff --git a/src/BloomExe/Program.cs b/src/BloomExe/Program.cs
index 2b20e1b6f46d..aedb5d91d59a 100644
--- a/src/BloomExe/Program.cs
+++ b/src/BloomExe/Program.cs
@@ -373,7 +373,7 @@ static int Main(string[] args1)
if (FolderTeamCollection.IsJoinTeamCollectionFile(args))
{
SetUpErrorHandling();
- string newCollection;
+ string newCollection = null;
// When we're spinning up a fake local collection in "projectName", we don't want
// any chance of copying FROM there to the repo.
TeamCollectionManager.ForceNextSyncToLocal = true;
@@ -394,69 +394,77 @@ static int Main(string[] args1)
Path.GetDirectoryName(args[0]),
fakeProjectFolder.FolderPath
);
- using (
- var projectContext = _applicationContainer.CreateProjectContext(
- fakeCollectionPath,
- true
- )
- )
+ if (fakeCollectionPath != null)
{
- if (!UniqueToken.AcquireTokenQuietly(_mutexId))
- {
- var msg = LocalizationManager.GetString(
- "TeamCollection.QuitOtherBloom",
- "Please close Bloom before joining a Team Collection"
- );
- BloomMessageBox.ShowInfo(msg);
- return 1;
- }
- _gotUniqueToken = true;
-
- if (
- projectContext.TeamCollectionManager.CurrentCollection
- == null
+ using (
+ var projectContext =
+ _applicationContainer.CreateProjectContext(
+ fakeCollectionPath,
+ true
+ )
)
{
- if (
- projectContext
- .TeamCollectionManager
- .CurrentCollectionEvenIfDisconnected != null
- )
+ if (!UniqueToken.AcquireTokenQuietly(_mutexId))
{
var msg = LocalizationManager.GetString(
- "TeamCollection.ConnectToJoin",
- "Bloom cannot currently join this collection."
+ "TeamCollection.QuitOtherBloom",
+ "Please close Bloom before joining a Team Collection"
);
- // This is a bit of a kludge, but when we make a disconnected collection it's pretty
- // consistently true that the last message just says "you'll be disconnected till you fix this",
- // but the previous one actually says what's wrong. So we'll reuse this in this (hopefully)
- // rare case.
- var messages =
- projectContext.TeamCollectionManager.CurrentCollectionEvenIfDisconnected.MessageLog.GetProgressMessages();
+ BloomMessageBox.ShowInfo(msg);
+ return 1;
+ }
+
+ _gotUniqueToken = true;
+
+ if (
+ projectContext.TeamCollectionManager.CurrentCollection
+ == null
+ )
+ {
if (
- messages.Length > 1
- && messages[messages.Length - 2].progressKind
- == "Error"
+ projectContext
+ .TeamCollectionManager
+ .CurrentCollectionEvenIfDisconnected != null
)
{
- msg +=
- Environment.NewLine
- + messages[messages.Length - 2].message;
+ var msg = LocalizationManager.GetString(
+ "TeamCollection.ConnectToJoin",
+ "Bloom cannot currently join this collection."
+ );
+ // This is a bit of a kludge, but when we make a disconnected collection it's pretty
+ // consistently true that the last message just says "you'll be disconnected till you fix this",
+ // but the previous one actually says what's wrong. So we'll reuse this in this (hopefully)
+ // rare case.
+ var messages =
+ projectContext.TeamCollectionManager.CurrentCollectionEvenIfDisconnected.MessageLog.GetProgressMessages();
+ if (
+ messages.Length > 1
+ && messages[messages.Length - 2].progressKind
+ == "Error"
+ )
+ {
+ msg +=
+ Environment.NewLine
+ + messages[messages.Length - 2].message;
+ }
+
+ ErrorReport.NotifyUserOfProblem(msg);
}
- ErrorReport.NotifyUserOfProblem(msg);
+
+ return 1; // something went wrong processing it, hopefully already reported.
}
- return 1; // something went wrong processing it, hopefully already reported.
+
+ newCollection =
+ FolderTeamCollection.ShowJoinCollectionTeamDialog(
+ args[0],
+ projectContext.TeamCollectionManager
+ );
}
- newCollection =
- FolderTeamCollection.ShowJoinCollectionTeamDialog(
- args[0],
- projectContext.TeamCollectionManager
- );
}
}
}
- if (newCollection == null) // user canceled
+ if (newCollection == null) // user canceled, or catastrophic problem already reported
return 1;
args = new string[] { }; // continue to open, but without args.
diff --git a/src/BloomExe/TeamCollection/FolderTeamCollection.cs b/src/BloomExe/TeamCollection/FolderTeamCollection.cs
index e79d0857b949..3969e6e01b88 100644
--- a/src/BloomExe/TeamCollection/FolderTeamCollection.cs
+++ b/src/BloomExe/TeamCollection/FolderTeamCollection.cs
@@ -13,6 +13,7 @@
using Bloom.web;
using L10NSharp;
using SIL.IO;
+using SIL.Reporting;
namespace Bloom.TeamCollection
{
@@ -550,6 +551,9 @@ protected override void CopyRepoCollectionFilesToLocalImpl(string destFolder)
// allows writing it but not moving/deleting it. But it seems the way our zip
// utility overwrites files involves something that is not allowed. We need to free
// it up while we do this.
+ // Note: I'm ignoring the remote possibility that CopyRepoCollectionFilesTo
+ // might fail or return false. If the repo files are for some reason not available,
+ // we will just carry on with the local ones as are they are (having notified the user).
_collectionLock.UnlockFor(() => CopyRepoCollectionFilesTo(destFolder, _repoFolderPath));
ExtractFolder(destFolder, _repoFolderPath, "Allowed Words");
ExtractFolder(destFolder, _repoFolderPath, "Sample Texts");
@@ -631,11 +635,23 @@ private static string MergeColorPaletteValues(string repoValues, string localVal
return string.Join(" ", localList);
}
- private static void CopyRepoCollectionFilesTo(string destFolder, string repoFolder)
+ // Returns true if it was able to do the copy. If false is returned, the user has been notified of the problem.
+ // Some callers may simply exit the program at that point, if not obtaining a local collection file is
+ // catastrophic, like when joining a team collection. Others may choose to ignore it.
+ private static bool CopyRepoCollectionFilesTo(string destFolder, string repoFolder)
{
var collectionZipPath = GetRepoProjectFilesZipPath(repoFolder);
if (!RobustFile.Exists(collectionZipPath))
- return;
+ {
+ // For now, TC messages are not being localized.
+ var msg = string.Format(
+ "This Team Collection is missing \"{0}\". See https://docs.bloomlibrary.org/team-collections-problems/",
+ collectionZipPath
+ );
+ ErrorReport.NotifyUserOfProblem(msg);
+ return false;
+ }
+
try
{
RobustZip.ExtractFolderFromZip(
@@ -654,7 +670,10 @@ private static void CopyRepoCollectionFilesTo(string destFolder, string repoFold
"Bloom could not unpack the collection files in your Team Collection",
exception: e
);
+ return false;
}
+
+ return true;
}
private static void SyncColorPaletteFileWithRepo(
@@ -1335,7 +1354,8 @@ public static string MissingTcPieces(string joinCollectionPath)
///
/// Called when the user clicks the Join{ and Merge} button in the dialog.
///
- /// an indication of the type of join for analytics
+ /// an indication of the type of join for analytics (or null if something
+ /// went catastrophically wrong and the join should be aborted)
public static string JoinCollectionTeam()
{
var repoFolder = Path.GetDirectoryName(_joinCollectionPath);
@@ -1376,6 +1396,8 @@ public static string JoinCollectionTeam()
repoFolder,
localCollectionFolder
);
+ if (string.IsNullOrEmpty(_newCollectionToJoin))
+ return null;
// Soon we will open the new collection, and do a SyncAtStartup. We want that to have some
// special behavior, but only if joining for the first time.
if (firstTimeJoin)
@@ -1388,6 +1410,7 @@ public static string JoinCollectionTeam()
/// in the specified repoFolder. (We could get away without unpacking more than the .bloomCollection
/// file, but we'll want the others soon, and typically it's not a lot.)
///
+ /// path to collection file, or null if something went catastrophically wrong
public static string SetupMinimumLocalCollectionFilesForRepo(
string repoFolder,
string localCollectionFolder
@@ -1395,7 +1418,8 @@ string localCollectionFolder
{
Directory.CreateDirectory(localCollectionFolder);
CreateTeamCollectionLinkFile(localCollectionFolder, repoFolder);
- CopyRepoCollectionFilesTo(localCollectionFolder, repoFolder);
+ if (!CopyRepoCollectionFilesTo(localCollectionFolder, repoFolder))
+ return null;
return CollectionPath(localCollectionFolder);
}
diff --git a/src/BloomExe/TeamCollection/TeamCollectionApi.cs b/src/BloomExe/TeamCollection/TeamCollectionApi.cs
index afd6ef446086..21870d01096c 100644
--- a/src/BloomExe/TeamCollection/TeamCollectionApi.cs
+++ b/src/BloomExe/TeamCollection/TeamCollectionApi.cs
@@ -360,18 +360,28 @@ private void HandleJoinTeamCollection(ApiRequest request)
{
var joinType = FolderTeamCollection.JoinCollectionTeam();
ReactDialog.CloseCurrentModal();
-
- Analytics.Track(
- "TeamCollectionJoin",
- new Dictionary()
- {
- { "CollectionId", _settings?.CollectionId },
- { "CollectionName", _settings?.CollectionName },
- { "Backend", _tcManager?.CurrentCollection?.GetBackendType() },
- { "User", CurrentUser },
- { "JoinType", joinType }, // create, open, or merge
- }
- );
+ // If this is null, something went badly wrong, and should have already been reported.
+ // We haven't joined the TC, so don't track it.
+ // This check was added in connection with problems when the TC we're trying to join
+ // doesn't have an "other" folder, or it doesn't have the zip that contains the .bloomCollection
+ // file. Such a problem will usually be detected and reported long before we open the
+ // dialog, so there's no likely path to this happening. The file would have to
+ // disappear between when we open the dialog and when we click the button to join.
+ // But we may as well handle the situation properly.
+ if (!string.IsNullOrEmpty(joinType))
+ {
+ Analytics.Track(
+ "TeamCollectionJoin",
+ new Dictionary()
+ {
+ { "CollectionId", _settings?.CollectionId },
+ { "CollectionName", _settings?.CollectionName },
+ { "Backend", _tcManager?.CurrentCollection?.GetBackendType() },
+ { "User", CurrentUser },
+ { "JoinType", joinType }, // create, open, or merge
+ }
+ );
+ }
request.PostSucceeded();
}