Browse code

BM-14923 Fix: missed.deletions ops on mailshare

David Phan authored on 12/06/2019 12:54:20
Showing 2 changed files
... ...
@@ -43,7 +43,8 @@ Require-Bundle: org.eclipse.core.runtime,
43 43
  net.bluemind.role.api,
44 44
  net.bluemind.core.sendmail,
45 45
  net.bluemind.core.task.service,
46
- net.bluemind.eclipse.common
46
+ net.bluemind.eclipse.common,
47
+ net.bluemind.group.api
47 48
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
48 49
 Bundle-ActivationPolicy: lazy
49 50
 Export-Package: net.bluemind.backend.mail.replica.service,
... ...
@@ -17,9 +17,11 @@
17 17
   */
18 18
 package net.bluemind.backend.mail.replica.service.internal.repair;
19 19
 
20
+import java.util.ArrayList;
20 21
 import java.util.Collection;
21 22
 import java.util.Collections;
22 23
 import java.util.List;
24
+import java.util.Optional;
23 25
 import java.util.Set;
24 26
 import java.util.UUID;
25 27
 import java.util.stream.Collectors;
... ...
@@ -38,21 +40,29 @@ import net.bluemind.backend.mail.replica.api.IDbReplicatedMailboxes;
38 40
 import net.bluemind.backend.mail.replica.api.IMailReplicaUids;
39 41
 import net.bluemind.backend.mail.replica.api.MailboxReplicaRootDescriptor.Namespace;
40 42
 import net.bluemind.backend.mail.replica.utils.SubtreeContainer;
43
+import net.bluemind.config.Token;
41 44
 import net.bluemind.core.api.report.DiagnosticReport;
45
+import net.bluemind.core.container.api.IContainerManagement;
42 46
 import net.bluemind.core.container.api.IContainers;
43 47
 import net.bluemind.core.container.model.ContainerDescriptor;
44 48
 import net.bluemind.core.container.model.ContainerModifiableDescriptor;
45 49
 import net.bluemind.core.container.model.ItemFlag;
46 50
 import net.bluemind.core.container.model.ItemValue;
51
+import net.bluemind.core.container.model.acl.AccessControlEntry;
52
+import net.bluemind.core.container.model.acl.Verb;
47 53
 import net.bluemind.core.rest.BmContext;
48 54
 import net.bluemind.core.task.service.IServerTaskMonitor;
49 55
 import net.bluemind.directory.api.BaseDirEntry.Kind;
50 56
 import net.bluemind.directory.api.DirEntry;
57
+import net.bluemind.directory.api.IDirectory;
51 58
 import net.bluemind.directory.api.MaintenanceOperation;
52 59
 import net.bluemind.directory.service.IDirEntryRepairSupport;
53 60
 import net.bluemind.directory.service.IDirEntryRepairSupport.InternalMaintenanceOperation;
61
+import net.bluemind.group.api.IGroup;
62
+import net.bluemind.group.api.Member;
54 63
 import net.bluemind.imap.IMAPException;
55 64
 import net.bluemind.imap.ListInfo;
65
+import net.bluemind.imap.ListResult;
56 66
 import net.bluemind.imap.NameSpaceInfo;
57 67
 import net.bluemind.imap.StoreClient;
58 68
 import net.bluemind.imap.TaggedResult;
... ...
@@ -76,7 +86,7 @@ public class ReApplyDeletionsRepair extends InternalMaintenanceOperation {
76 86
 
77 87
 				@Override
78 88
 				public Set<MaintenanceOperation> availableOperations(Kind kind) {
79
-					if (kind == Kind.USER) {
89
+					if (kind == Kind.USER || kind == Kind.MAILSHARE) {
80 90
 						return Sets.newHashSet(op);
81 91
 					} else {
82 92
 						return Collections.emptySet();
... ...
@@ -85,7 +95,7 @@ public class ReApplyDeletionsRepair extends InternalMaintenanceOperation {
85 95
 
86 96
 				@Override
87 97
 				public Set<InternalMaintenanceOperation> ops(Kind kind) {
88
-					if (kind == Kind.USER) {
98
+					if (kind == Kind.USER || kind == Kind.MAILSHARE) {
89 99
 						return Sets.newHashSet(new ReApplyDeletionsRepair(context));
90 100
 					} else {
91 101
 						return Collections.emptySet();
... ...
@@ -145,7 +155,7 @@ public class ReApplyDeletionsRepair extends InternalMaintenanceOperation {
145 155
 			}
146 156
 
147 157
 			@Override
148
-			public void postProcessing(UserMailApi mailApi, String flag, StoreClient sc, List<ListInfo> folders)
158
+			public void postProcessing(MboxContext mailApi, String flag, StoreClient sc, List<ListInfo> folders)
149 159
 					throws IMAPException {
150 160
 				for (ListInfo li : folders) {
151 161
 					monitor.progress(1, "Cleanup " + li.getName());
... ...
@@ -157,9 +167,9 @@ public class ReApplyDeletionsRepair extends InternalMaintenanceOperation {
157 167
 						String set = deleted.stream().map(Object::toString).collect(Collectors.joining(","));
158 168
 						String cmd = "UID STORE " + set + " -FLAGS.SILENT (" + flag + ")";
159 169
 						TaggedResult ok = sc.tagged(cmd);
160
-						monitor.log("Updated " + deleted.size() + " message(s) => " + ok.isOk());
170
+						monitor.log("(imap) Updated " + deleted.size() + " message(s) => " + ok.isOk());
161 171
 						sc.expunge();
162
-						monitor.log("Resync mailbox record(s)");
172
+						monitor.log("(imap) Resync mailbox record(s)");
163 173
 					}
164 174
 				}
165 175
 				IMailboxFoldersByContainer subApi = mailApi.ctx.provider().instance(IMailboxFoldersByContainer.class,
... ...
@@ -167,6 +177,7 @@ public class ReApplyDeletionsRepair extends InternalMaintenanceOperation {
167 177
 				for (ItemValue<MailboxFolder> f : subApi.all()) {
168 178
 					IMailboxItems recsApi = mailApi.ctx.provider().instance(IMailboxItems.class, f.uid);
169 179
 					recsApi.resync();
180
+					monitor.log("Resync mailbox " + f.displayName);
170 181
 				}
171 182
 			}
172 183
 
... ...
@@ -186,11 +197,11 @@ public class ReApplyDeletionsRepair extends InternalMaintenanceOperation {
186 197
 		run(op, domainUid, entry, monitor);
187 198
 	}
188 199
 
189
-	private static class UserMailApi {
200
+	private static class MboxContext {
190 201
 		private final BmContext ctx;
191 202
 		private final String subtree;
192 203
 
193
-		public UserMailApi(String subtree, BmContext userCtx) {
204
+		public MboxContext(String subtree, BmContext userCtx) {
194 205
 			this.subtree = subtree;
195 206
 			this.ctx = userCtx;
196 207
 		}
... ...
@@ -206,6 +217,99 @@ public class ReApplyDeletionsRepair extends InternalMaintenanceOperation {
206 217
 
207 218
 		processDbMailboxData(op, domainUid, mbox);
208 219
 
220
+		if (mbox.value.type.sharedNs) {
221
+			runOnSharedMailbox(op, domainUid, monitor, mbox);
222
+		} else {
223
+			runOnUserMailbox(op, domainUid, monitor, mbox);
224
+		}
225
+
226
+	}
227
+
228
+	private void runOnSharedMailbox(ReApplyDeletion op, String domainUid, IServerTaskMonitor monitor,
229
+			ItemValue<Mailbox> mbox) {
230
+		ItemValue<Server> backend = Topology.get().datalocation(mbox.value.dataLocation);
231
+
232
+		String entryUid = getMailshareWriter(domainUid, mbox);
233
+
234
+		if (entryUid == null) {
235
+			monitor.log("mailshare is not writable");
236
+			return;
237
+		}
238
+
239
+		BmContext userCtx = context.su("repair-" + UUID.randomUUID().toString(), entryUid, domainUid);
240
+
241
+		try (StoreClient sc = new StoreClient(backend.value.address(), 1143, "admin0", Token.admin0())) {
242
+			if (!sc.login()) {
243
+				logger.error("Failed to connect {}", mbox.value.name);
244
+				monitor.log("Failed to connect " + mbox.value.name);
245
+				return;
246
+			}
247
+
248
+			String mboxName = mbox.value.name + "@" + domainUid;
249
+
250
+			ListResult folders = sc.listSubFoldersMailbox(mboxName);
251
+			// add mbox root
252
+			folders.add(new ListInfo(mboxName, true));
253
+
254
+			String flag = "ReApplyDeletionsRepair" + Long.toHexString(System.currentTimeMillis());
255
+			String subtree = SubtreeContainer.mailSubtreeUid(domainUid, Namespace.shared, mbox.uid).subtreeUid;
256
+			MboxContext mailApi = new MboxContext(subtree, userCtx);
257
+			processFolders(op, mailApi, monitor, flag, sc, folders);
258
+
259
+		} catch (Exception e) {
260
+			logger.error(e.getMessage(), e);
261
+			monitor.log("Failed to repair mailshare " + mbox.uid + ": " + e.getMessage());
262
+
263
+		}
264
+
265
+	}
266
+
267
+	/**
268
+	 * Returns one user with write right on the mailshare
269
+	 * 
270
+	 * @param domainUid
271
+	 * @param mbox
272
+	 * @return
273
+	 */
274
+	private String getMailshareWriter(String domainUid, ItemValue<Mailbox> mbox) {
275
+		IContainerManagement service = context.su().provider().instance(IContainerManagement.class,
276
+				"mailbox:acls-" + mbox.uid);
277
+		List<AccessControlEntry> accessControlList = new ArrayList<>(service.getAccessControlList());
278
+
279
+		List<String> writers = accessControlList.stream().filter(entity -> entity.verb.can(Verb.Write))
280
+				.map(entry -> entry.subject).collect(Collectors.toList());
281
+
282
+		if (writers.isEmpty()) {
283
+			return null;
284
+		}
285
+		IDirectory dir = context.su().provider().instance(IDirectory.class, domainUid);
286
+		List<ItemValue<DirEntry>> entries = dir.getMultiple(writers);
287
+
288
+		Optional<ItemValue<DirEntry>> dirEntry = entries.stream().filter(de -> de.value.kind == Kind.USER).findFirst();
289
+		String entryUid = null;
290
+		if (!dirEntry.isPresent()) {
291
+			IGroup groupService = context.su().provider().instance(IGroup.class, domainUid);
292
+			List<ItemValue<DirEntry>> groups = entries.stream().filter(de -> de.value.kind == Kind.GROUP)
293
+					.collect(Collectors.toList());
294
+
295
+			for (int i = 0; i < groups.size(); i++) {
296
+				ItemValue<DirEntry> g = groups.get(i);
297
+				List<Member> members = groupService.getExpandedUserMembers(g.uid);
298
+				if (!members.isEmpty()) {
299
+					entryUid = members.get(0).uid;
300
+					break;
301
+				}
302
+
303
+			}
304
+
305
+		} else {
306
+			entryUid = dirEntry.get().uid;
307
+		}
308
+		return entryUid;
309
+	}
310
+
311
+	private void runOnUserMailbox(ReApplyDeletion op, String domainUid, IServerTaskMonitor monitor,
312
+			ItemValue<Mailbox> mbox) {
209 313
 		String latd = mbox.value.name + "@" + domainUid;
210 314
 		LoginResponse resp = context.provider().instance(IAuthentication.class).su(latd);
211 315
 		if (resp.authKey != null) {
... ...
@@ -230,7 +334,7 @@ public class ReApplyDeletionsRepair extends InternalMaintenanceOperation {
230 334
 				}).collect(Collectors.toList());
231 335
 				String subtree = SubtreeContainer.mailSubtreeUid(domainUid, Namespace.users, mbox.uid).subtreeUid;
232 336
 				BmContext userCtx = context.su("repair-" + UUID.randomUUID().toString(), mbox.uid, domainUid);
233
-				UserMailApi mailApi = new UserMailApi(subtree, userCtx);
337
+				MboxContext mailApi = new MboxContext(subtree, userCtx);
234 338
 				processFolders(op, mailApi, monitor, flag, sc, folders);
235 339
 			} catch (Exception e) {
236 340
 				logger.error(e.getMessage(), e);
... ...
@@ -238,7 +342,6 @@ public class ReApplyDeletionsRepair extends InternalMaintenanceOperation {
238 342
 		} else {
239 343
 			monitor.log("Sudo failed for " + latd);
240 344
 		}
241
-
242 345
 	}
243 346
 
244 347
 	private void processDbMailboxData(ReApplyDeletion op, String domainUid, ItemValue<Mailbox> mbox) {
... ...
@@ -257,6 +360,9 @@ public class ReApplyDeletionsRepair extends InternalMaintenanceOperation {
257 360
 	}
258 361
 
259 362
 	private String mboxRoot(ItemValue<Mailbox> mbox) {
363
+		if (mbox.value.type.sharedNs) {
364
+			return mbox.value.name.replace(".", "^");
365
+		}
260 366
 		return "user." + mbox.value.name.replace(".", "^");
261 367
 	}
262 368
 
... ...
@@ -264,7 +370,7 @@ public class ReApplyDeletionsRepair extends InternalMaintenanceOperation {
264 370
 		return domainUid.replace(".", "_");
265 371
 	}
266 372
 
267
-	private void processFolders(ReApplyDeletion op, UserMailApi mailApi, IServerTaskMonitor monitor, String flag,
373
+	private void processFolders(ReApplyDeletion op, MboxContext mailApi, IServerTaskMonitor monitor, String flag,
268 374
 			StoreClient sc, List<ListInfo> folders) throws IMAPException {
269 375
 		monitor.begin(2d * folders.size(), "Processing " + folders.size() + " folder(s)");
270 376
 		for (ListInfo li : folders) {
... ...
@@ -287,7 +393,7 @@ public class ReApplyDeletionsRepair extends InternalMaintenanceOperation {
287 393
 
288 394
 		public void applyDeletion(Collection<Integer> uids, String flag, StoreClient sc, ListInfo listInfo);
289 395
 
290
-		public default void postProcessing(UserMailApi mailApi, String flag, StoreClient sc, List<ListInfo> folders)
396
+		public default void postProcessing(MboxContext mailApi, String flag, StoreClient sc, List<ListInfo> folders)
291 397
 				throws IMAPException {
292 398
 		}
293 399