blob: 093edb681980e909ce6276a7e59fa1b8c0f1a330 [file] [log] [blame]
/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
****************************************************************/
package org.apache.james.adapter.mailbox;
import java.util.Optional;
import jakarta.inject.Inject;
import org.apache.james.core.Username;
import org.apache.james.mailbox.MailboxManager;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.SubscriptionManager;
import org.apache.james.mailbox.exception.SubscriptionException;
import org.apache.james.mailbox.model.MailboxACL;
import org.apache.james.mailbox.model.MailboxMetaData;
import org.apache.james.mailbox.model.search.MailboxQuery;
import org.apache.james.user.api.UsernameChangeTaskStep;
import org.apache.james.util.ReactorUtils;
import org.reactivestreams.Publisher;
import com.github.fge.lambdas.Throwing;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public class ACLUsernameChangeTaskStep implements UsernameChangeTaskStep {
private final MailboxManager mailboxManager;
private final SubscriptionManager subscriptionManager;
@Inject
public ACLUsernameChangeTaskStep(MailboxManager mailboxManager, SubscriptionManager subscriptionManager) {
this.mailboxManager = mailboxManager;
this.subscriptionManager = subscriptionManager;
}
@Override
public StepName name() {
return new StepName("ACLUsernameChangeTaskStep");
}
@Override
public int priority() {
return 3;
}
@Override
public Publisher<Void> changeUsername(Username oldUsername, Username newUsername) {
MailboxSession oldSession = mailboxManager.createSystemSession(oldUsername);
MailboxSession newSession = mailboxManager.createSystemSession(newUsername);
return mailboxManager.search(MailboxQuery.builder().matchesAllMailboxNames().build(), oldSession)
.filter(mailbox -> !mailbox.getPath().getUser().equals(oldUsername))
.concatMap(mailbox -> migrateACLs(oldUsername, newUsername, mailbox))
.then(updateSubscriptionsOnDeletedMailboxes(oldUsername, oldSession, newSession))
.doFinally(any -> mailboxManager.endProcessingRequest(oldSession))
.doFinally(any -> mailboxManager.endProcessingRequest(newSession));
}
private Mono<Void> updateSubscriptionsOnDeletedMailboxes(Username oldUsername, MailboxSession oldSession, MailboxSession newSession) {
try {
return Flux.from(subscriptionManager.subscriptionsReactive(oldSession))
.filter(subscription -> !subscription.getUser().equals(oldUsername))
.concatMap(subscription -> Mono.from(subscriptionManager.subscribeReactive(subscription, newSession))
.then(Mono.from(subscriptionManager.unsubscribeReactive(subscription, oldSession))))
.then();
} catch (SubscriptionException e) {
return Mono.error(e);
}
}
private Publisher<? extends Void> migrateACLs(Username oldUsername, Username newUsername, MailboxMetaData mailbox) {
MailboxSession ownerSession = mailboxManager.createSystemSession(mailbox.getPath().getUser());
MailboxACL.Rfc4314Rights rights = Optional.ofNullable(mailbox.getMailbox().getACL().getEntries().get(MailboxACL.EntryKey.createUserEntryKey(oldUsername)))
.orElse(MailboxACL.NO_RIGHTS);
return Mono.fromRunnable(Throwing.runnable(() -> mailboxManager.applyRightsCommand(mailbox.getId(), MailboxACL.command().rights(rights).forUser(newUsername).asAddition(), ownerSession)))
.then(Mono.fromRunnable(Throwing.runnable(() -> mailboxManager.applyRightsCommand(mailbox.getId(), MailboxACL.command().rights(rights).forUser(oldUsername).asRemoval(), ownerSession))))
.subscribeOn(ReactorUtils.BLOCKING_CALL_WRAPPER)
.then()
.doFinally(any -> mailboxManager.endProcessingRequest(ownerSession));
}
}