This is an automated email from the ASF dual-hosted git repository. rcordier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 24482cc489fbeb65be1cf57de51dd63390fc4f14 Author: Rene Cordier <[email protected]> AuthorDate: Thu May 21 10:18:20 2020 +0700 JAMES-3171 Port MailboxFactory to jmap-rfc8621 --- .../scala/org/apache/james/jmap/mail/Mailbox.scala | 48 ++++++-- .../apache/james/jmap/model/MailboxFactory.scala | 125 +++++++++++++++++++++ .../james/jmap/json/MailboxSerializationTest.scala | 2 +- 3 files changed, 162 insertions(+), 13 deletions(-) diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Mailbox.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Mailbox.scala index aaff40e..fc03a7b 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Mailbox.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/Mailbox.scala @@ -19,11 +19,12 @@ package org.apache.james.jmap.mail +import eu.timepit.refined import eu.timepit.refined.api.Refined import eu.timepit.refined.auto._ import eu.timepit.refined.collection.NonEmpty import org.apache.james.core.Username -import org.apache.james.jmap.mail.Mailbox.MailboxName +import org.apache.james.jmap.mail.MailboxName.MailboxName import org.apache.james.jmap.model.UnsignedInt.UnsignedInt import org.apache.james.mailbox.Role import org.apache.james.mailbox.model.MailboxId @@ -38,15 +39,29 @@ case class MayRename(value: Boolean) extends AnyVal case class MayDelete(value: Boolean) extends AnyVal case class MaySubmit(value: Boolean) extends AnyVal +object MailboxRights { + val FULL: MailboxRights = MailboxRights( + mayReadItems = MayReadItems(true), + mayAddItems = MayAddItems(true), + mayRemoveItems = MayRemoveItems(true), + maySetSeen = MaySetSeen(true), + maySetKeywords = MaySetKeywords(true), + mayCreateChild = MayCreateChild(true), + mayRename = MayRename(true), + mayDelete = MayDelete(true), + maySubmit = MaySubmit(true), + ) +} + case class MailboxRights(mayReadItems: MayReadItems, - mayAddItems: MayAddItems, - mayRemoveItems: MayRemoveItems, - maySetSeen: MaySetSeen, - maySetKeywords: MaySetKeywords, - mayCreateChild: MayCreateChild, - mayRename: MayRename, - mayDelete: MayDelete, - maySubmit: MaySubmit) + mayAddItems: MayAddItems, + mayRemoveItems: MayRemoveItems, + maySetSeen: MaySetSeen, + maySetKeywords: MaySetKeywords, + mayCreateChild: MayCreateChild, + mayRename: MayRename, + mayDelete: MayDelete, + maySubmit: MaySubmit) object MailboxNamespace { def delegated(owner: Username) = DelegatedNamespace(owner) @@ -61,6 +76,8 @@ case class PersonalNamespace() extends MailboxNamespace case class DelegatedNamespace(owner: Username) extends MailboxNamespace object SortOrder { + val defaultSortOrder: SortOrder = SortOrder(1000L) + private val defaultSortOrders = Map( Role.INBOX -> SortOrder(10L), Role.ARCHIVE -> SortOrder(20L), @@ -71,7 +88,7 @@ object SortOrder { Role.SPAM -> SortOrder(70L), Role.TEMPLATES -> SortOrder(80L), Role.RESTORED_MESSAGES -> SortOrder(90L)) - .withDefaultValue(SortOrder(1000L)) + .withDefaultValue(defaultSortOrder) def getSortOrder(role: Role): SortOrder = defaultSortOrders(role) } @@ -97,8 +114,15 @@ sealed trait QuotasExtension extends MailboxExtensionAdditionalFields { def quotas: Quotas } -object Mailbox { - type MailboxName = String Refined NonEmpty +object MailboxName { + type MailboxNameConstraint = NonEmpty + type MailboxName = String Refined MailboxNameConstraint + + def liftOrThrow(value: String): MailboxName = + refined.refineV[MailboxNameConstraint](value) match { + case scala.util.Right(value) => value + case Left(error) => throw new IllegalArgumentException(error) + } } case class Mailbox(id: MailboxId, diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/MailboxFactory.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/MailboxFactory.scala new file mode 100644 index 0000000..caf9046 --- /dev/null +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/MailboxFactory.scala @@ -0,0 +1,125 @@ +/**************************************************************** + * 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.jmap.model + +import javax.inject.Inject +import org.apache.james.jmap.mail.MailboxName.MailboxName +import org.apache.james.jmap.mail._ +import org.apache.james.jmap.utils.quotas.QuotaLoader +import org.apache.james.mailbox.model.MailboxACL.EntryKey +import org.apache.james.mailbox.model.{MailboxCounters, MailboxId, MailboxMetaData, MailboxPath, MailboxACL => JavaMailboxACL} +import org.apache.james.mailbox.{MailboxSession, Role, SubscriptionManager} +import reactor.core.scala.publisher.SMono + +import scala.jdk.CollectionConverters._ +import scala.jdk.OptionConverters._ + +sealed trait MailboxConstructionOrder + +class Factory + +class MailboxFactory @Inject() (subscriptionManager: SubscriptionManager) { + + def create(mailboxMetaData: MailboxMetaData, + mailboxSession: MailboxSession, + allMailboxesMetadata: Seq[MailboxMetaData], + quotaLoader: QuotaLoader): SMono[Mailbox] = { + + val id: MailboxId = mailboxMetaData.getId + + val name: MailboxName = MailboxName.liftOrThrow(mailboxMetaData.getPath + .getName + .split(mailboxSession.getPathDelimiter) + .last) + + val role: Option[Role] = Role.from(mailboxMetaData.getPath.getName) + .filter(_ => mailboxMetaData.getPath.belongsTo(mailboxSession)).toScala + val sortOrder: SortOrder = role.map(SortOrder.getSortOrder).getOrElse(SortOrder.defaultSortOrder) + val quotas: SMono[Quotas] = quotaLoader.getQuotas(mailboxMetaData.getPath) + val rights: Rights = Rights.fromACL(MailboxACL.fromJava(mailboxMetaData.getResolvedAcls)) + + val sanitizedCounters: MailboxCounters = mailboxMetaData.getCounters.sanitize() + val unreadEmails: UnreadEmails = UnreadEmails(UnsignedInt.liftOrThrow(sanitizedCounters.getUnseen)) + val unreadThreads: UnreadThreads = UnreadThreads(UnsignedInt.liftOrThrow(sanitizedCounters.getUnseen)) + val totalEmails: TotalEmails = TotalEmails(UnsignedInt.liftOrThrow(sanitizedCounters.getCount)) + val totalThreads: TotalThreads = TotalThreads(UnsignedInt.liftOrThrow(sanitizedCounters.getCount)) + + val isOwner = mailboxMetaData.getPath.belongsTo(mailboxSession) + val aclEntryKey: EntryKey = EntryKey.createUserEntryKey(mailboxSession.getUser) + + val namespace: MailboxNamespace = if (isOwner) { + PersonalNamespace() + } else { + DelegatedNamespace(mailboxMetaData.getPath.getUser) + } + + val parentPath: Option[MailboxPath] = + mailboxMetaData.getPath + .getHierarchyLevels(mailboxSession.getPathDelimiter) + .asScala + .reverse + .drop(1) + .headOption + + val parentId: Option[MailboxId] = allMailboxesMetadata.filter(otherMetadata => parentPath.contains(otherMetadata.getPath)) + .map(_.getId) + .headOption + + val myRights: MailboxRights = if (isOwner) { + MailboxRights.FULL + } else { + val rights = Rfc4314Rights.fromJava(mailboxMetaData.getResolvedAcls + .getEntries + .getOrDefault(aclEntryKey, JavaMailboxACL.NO_RIGHTS)) + .toRights + MailboxRights( + mayReadItems = MayReadItems(rights.contains(Right.Read)), + mayAddItems = MayAddItems(rights.contains(Right.Insert)), + mayRemoveItems = MayRemoveItems(rights.contains(Right.DeleteMessages)), + maySetSeen = MaySetSeen(rights.contains(Right.Seen)), + maySetKeywords = MaySetKeywords(rights.contains(Right.Write)), + mayCreateChild = MayCreateChild(false), + mayRename = MayRename(false), + mayDelete = MayDelete(false), + maySubmit = MaySubmit(false)) + } + + def retrieveIsSubscribed: IsSubscribed = IsSubscribed(subscriptionManager + .subscriptions(mailboxSession) + .contains(mailboxMetaData.getPath.getName)) + + SMono.fromPublisher(quotas) + .map(quotas => Mailbox( + id = id, + name = name, + parentId = parentId, + role = role, + sortOrder = sortOrder, + unreadEmails = unreadEmails, + totalEmails = totalEmails, + unreadThreads = unreadThreads, + totalThreads = totalThreads, + myRights = myRights, + namespace = namespace, + rights = rights, + quotas = quotas, + isSubscribed = retrieveIsSubscribed)) + } +} \ No newline at end of file diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxSerializationTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxSerializationTest.scala index 940d29a..c5b49d8 100644 --- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxSerializationTest.scala +++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxSerializationTest.scala @@ -23,7 +23,7 @@ import eu.timepit.refined.auto._ import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson import org.apache.james.core.{Domain, Username} import org.apache.james.jmap.json.MailboxSerializationTest.MAILBOX -import org.apache.james.jmap.mail.Mailbox.MailboxName +import org.apache.james.jmap.mail.MailboxName.MailboxName import org.apache.james.jmap.mail.{IsSubscribed, Mailbox, MailboxNamespace, MailboxRights, MayAddItems, MayCreateChild, MayDelete, MayReadItems, MayRemoveItems, MayRename, MaySetKeywords, MaySetSeen, MaySubmit, PersonalNamespace, Quota, QuotaId, QuotaRoot, Quotas, Right, Rights, SortOrder, TotalEmails, TotalThreads, UnreadEmails, UnreadThreads, Value} import org.apache.james.mailbox.Role import org.apache.james.mailbox.model.{MailboxId, TestId} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
