|
47 | 47 | using SIL.XForge.Services; |
48 | 48 | using SIL.XForge.Utils; |
49 | 49 | using StringUtils = SIL.XForge.Utils.StringUtils; |
| 50 | +using TextInfo = SIL.XForge.Scripture.Models.TextInfo; |
50 | 51 |
|
51 | 52 | namespace SIL.XForge.Scripture.Services; |
52 | 53 |
|
@@ -331,6 +332,7 @@ SyncMetrics syncMetrics |
331 | 332 | syncMetrics.ParatextBooks != new SyncMetricInfo() |
332 | 333 | || syncMetrics.ParatextNotes != new SyncMetricInfo() |
333 | 334 | || syncMetrics.ParatextBiblicalTerms != new SyncMetricInfo() |
| 335 | + || syncMetrics.ParatextPermissions != new SyncMetricInfo() |
334 | 336 | ) |
335 | 337 | ) |
336 | 338 | { |
@@ -1690,6 +1692,107 @@ IReadOnlyList<BiblicalTerm> biblicalTerms |
1690 | 1692 | return syncMetricInfo; |
1691 | 1693 | } |
1692 | 1694 |
|
| 1695 | + public async Task<SyncMetricInfo> UpdateParatextPermissionsForNewBooksAsync( |
| 1696 | + UserSecret userSecret, |
| 1697 | + string paratextId, |
| 1698 | + IDocument<SFProject> projectDoc, |
| 1699 | + bool writeToParatext |
| 1700 | + ) |
| 1701 | + { |
| 1702 | + var syncMetricInfo = new SyncMetricInfo(); |
| 1703 | + using ScrText scrText = ScrTextCollection.FindById(GetParatextUsername(userSecret)!, paratextId); |
| 1704 | + if (scrText is null) |
| 1705 | + { |
| 1706 | + return syncMetricInfo; |
| 1707 | + } |
| 1708 | + |
| 1709 | + if (!projectDoc.Data.Editable) |
| 1710 | + { |
| 1711 | + return syncMetricInfo; |
| 1712 | + } |
| 1713 | + |
| 1714 | + // Get all projects that are not on disk |
| 1715 | + for (int i = 0; i < projectDoc.Data.Texts.Count; i++) |
| 1716 | + { |
| 1717 | + TextInfo text = projectDoc.Data.Texts[i]; |
| 1718 | + int bookNum = text.BookNum; |
| 1719 | + if (scrText.BookPresent(bookNum)) |
| 1720 | + { |
| 1721 | + // Book is on disk, skip to the next book |
| 1722 | + continue; |
| 1723 | + } |
| 1724 | + |
| 1725 | + // Add any users to the book who would have the ability to access it |
| 1726 | + foreach (var user in projectDoc.Data.ParatextUsers) |
| 1727 | + { |
| 1728 | + // If there is no SF user id or PT username, ignore this user |
| 1729 | + if (string.IsNullOrEmpty(user.SFUserId) || string.IsNullOrEmpty(user.Username)) |
| 1730 | + { |
| 1731 | + continue; |
| 1732 | + } |
| 1733 | + |
| 1734 | + bool hasPermissionInParatext = scrText.Permissions.CanEdit(bookNum, chapterNum: 0, user.Username); |
| 1735 | + bool hasPermissionInMongo = |
| 1736 | + text.Permissions.TryGetValue(user.SFUserId, out string permission) |
| 1737 | + && permission == TextInfoPermission.Write; |
| 1738 | + bool userIsAdministrator = scrText.Permissions.GetUser(user.Username)?.Role == UserRoles.Administrator; |
| 1739 | + |
| 1740 | + if (writeToParatext) |
| 1741 | + { |
| 1742 | + // Grant the user access to edit the new book, if we granted them access in Mongo, |
| 1743 | + // they are an administrator, but they do not have access in Paratext. |
| 1744 | + // |
| 1745 | + // This is based on ParatextData.ImportSfmText.GrantBookPermissions() |
| 1746 | + if (hasPermissionInMongo && !hasPermissionInParatext && userIsAdministrator) |
| 1747 | + { |
| 1748 | + scrText.Permissions.SetPermission(user.Username, bookNum, PermissionSet.Manual, true); |
| 1749 | + syncMetricInfo.Updated++; |
| 1750 | + } |
| 1751 | + } |
| 1752 | + else |
| 1753 | + { |
| 1754 | + // If the user can edit the book and doesn't have permission, |
| 1755 | + // or they are the current user and an administrator, |
| 1756 | + // update the Scripture Forge permissions to allow writing. |
| 1757 | + bool currentUserIsAdministrator = userIsAdministrator && user.SFUserId == userSecret.Id; |
| 1758 | + if (!hasPermissionInMongo && (currentUserIsAdministrator || hasPermissionInParatext)) |
| 1759 | + { |
| 1760 | + // Add the user to the new book in SF with book permissions and available chapter permissions |
| 1761 | + // This will be empty if the current user is an administrator but has no permissions for the book |
| 1762 | + int[] editableChapters = |
| 1763 | + [ |
| 1764 | + .. scrText.Permissions.GetEditableChapters( |
| 1765 | + bookNum, |
| 1766 | + scrText.Settings.Versification, |
| 1767 | + user.Username |
| 1768 | + ) ?? [], |
| 1769 | + ]; |
| 1770 | + await projectDoc.SubmitJson0OpAsync(op => |
| 1771 | + { |
| 1772 | + int textIndex = i; |
| 1773 | + op.Set(p => p.Texts[textIndex].Permissions[user.SFUserId], TextInfoPermission.Write); |
| 1774 | + for (int j = 0; j < text.Chapters.Count; j++) |
| 1775 | + { |
| 1776 | + int chapterIndex = j; |
| 1777 | + int chapterNumber = text.Chapters[chapterIndex].Number; |
| 1778 | + if (editableChapters.Contains(chapterNumber) || currentUserIsAdministrator) |
| 1779 | + { |
| 1780 | + op.Set( |
| 1781 | + p => p.Texts[textIndex].Chapters[chapterIndex].Permissions[user.SFUserId], |
| 1782 | + TextInfoPermission.Write |
| 1783 | + ); |
| 1784 | + } |
| 1785 | + } |
| 1786 | + }); |
| 1787 | + syncMetricInfo.Updated++; |
| 1788 | + } |
| 1789 | + } |
| 1790 | + } |
| 1791 | + } |
| 1792 | + |
| 1793 | + return syncMetricInfo; |
| 1794 | + } |
| 1795 | + |
1693 | 1796 | /// <summary> |
1694 | 1797 | /// Get the most recent revision id of a commit from the last push or pull with the PT send/receive server. |
1695 | 1798 | /// </summary> |
|
0 commit comments