mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-21 18:08:25 +00:00
Starting with mail functionality
This commit is contained in:
34
modules/store/src/main/scala/docspell/store/EmilUtil.scala
Normal file
34
modules/store/src/main/scala/docspell/store/EmilUtil.scala
Normal file
@ -0,0 +1,34 @@
|
||||
package docspell.store
|
||||
|
||||
import emil._
|
||||
import emil.javamail.syntax._
|
||||
|
||||
object EmilUtil {
|
||||
|
||||
def readSSLType(str: String): Either[String, SSLType] =
|
||||
str.toLowerCase match {
|
||||
case "ssl" => Right(SSLType.SSL)
|
||||
case "starttls" => Right(SSLType.StartTLS)
|
||||
case "none" => Right(SSLType.NoEncryption)
|
||||
case _ => Left(s"Invalid ssl-type: $str")
|
||||
}
|
||||
|
||||
def unsafeReadSSLType(str: String): SSLType =
|
||||
readSSLType(str).fold(sys.error, identity)
|
||||
|
||||
def sslTypeString(st: SSLType): String =
|
||||
st match {
|
||||
case SSLType.SSL => "ssl"
|
||||
case SSLType.StartTLS => "starttls"
|
||||
case SSLType.NoEncryption => "none"
|
||||
}
|
||||
|
||||
def readMailAddress(str: String): Either[String, MailAddress] =
|
||||
MailAddress.parse(str)
|
||||
|
||||
def unsafeReadMailAddress(str: String): MailAddress =
|
||||
readMailAddress(str).fold(sys.error, identity)
|
||||
|
||||
def mailAddressString(ma: MailAddress): String =
|
||||
ma.asUnicodeString
|
||||
}
|
@ -2,18 +2,15 @@ package docspell.store.impl
|
||||
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.{Instant, LocalDate}
|
||||
|
||||
import docspell.common.Timestamp
|
||||
|
||||
import docspell.common._
|
||||
import io.circe.{Decoder, Encoder}
|
||||
import doobie._
|
||||
//import doobie.implicits.javatime._
|
||||
import doobie.implicits.legacy.instant._
|
||||
import doobie.util.log.Success
|
||||
import io.circe.{Decoder, Encoder}
|
||||
import docspell.common.syntax.all._
|
||||
import emil.{MailAddress, SSLType}
|
||||
import emil.javamail.syntax._
|
||||
|
||||
import docspell.common._
|
||||
import docspell.common.syntax.all._
|
||||
import docspell.store.EmilUtil
|
||||
|
||||
trait DoobieMeta {
|
||||
|
||||
@ -92,29 +89,14 @@ trait DoobieMeta {
|
||||
Meta[String].imap(Language.unsafe)(_.iso3)
|
||||
|
||||
implicit val sslType: Meta[SSLType] =
|
||||
Meta[String].imap(DoobieMeta.readSSLType)(DoobieMeta.sslTypeString)
|
||||
Meta[String].imap(EmilUtil.unsafeReadSSLType)(EmilUtil.sslTypeString)
|
||||
|
||||
implicit val mailAddress: Meta[MailAddress] =
|
||||
Meta[String].imap(str => MailAddress.parse(str).fold(sys.error, identity))(_.asUnicodeString)
|
||||
Meta[String].imap(EmilUtil.unsafeReadMailAddress)(EmilUtil.mailAddressString)
|
||||
}
|
||||
|
||||
object DoobieMeta extends DoobieMeta {
|
||||
import org.log4s._
|
||||
private val logger = getLogger
|
||||
|
||||
private def readSSLType(str: String): SSLType =
|
||||
str.toLowerCase match {
|
||||
case "ssl" => SSLType.SSL
|
||||
case "starttls" => SSLType.StartTLS
|
||||
case "none" => SSLType.NoEncryption
|
||||
case _ => sys.error(s"Invalid ssl-type: $str")
|
||||
}
|
||||
|
||||
private def sslTypeString(st: SSLType): String =
|
||||
st match {
|
||||
case SSLType.SSL => "ssl"
|
||||
case SSLType.StartTLS => "starttls"
|
||||
case SSLType.NoEncryption => "none"
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,9 @@ package docspell.store.records
|
||||
|
||||
import doobie._
|
||||
import doobie.implicits._
|
||||
import cats.effect._
|
||||
import cats.implicits._
|
||||
import cats.data.OptionT
|
||||
import docspell.common._
|
||||
import docspell.store.impl.Column
|
||||
import docspell.store.impl.Implicits._
|
||||
@ -10,11 +13,11 @@ import emil.{MailAddress, SSLType}
|
||||
case class RUserEmail(
|
||||
id: Ident,
|
||||
uid: Ident,
|
||||
name: String,
|
||||
name: Ident,
|
||||
smtpHost: String,
|
||||
smtpPort: Int,
|
||||
smtpUser: String,
|
||||
smtpPassword: Password,
|
||||
smtpPort: Option[Int],
|
||||
smtpUser: Option[String],
|
||||
smtpPassword: Option[Password],
|
||||
smtpSsl: SSLType,
|
||||
smtpCertCheck: Boolean,
|
||||
mailFrom: MailAddress,
|
||||
@ -24,6 +27,67 @@ case class RUserEmail(
|
||||
|
||||
object RUserEmail {
|
||||
|
||||
def apply[F[_]: Sync](
|
||||
uid: Ident,
|
||||
name: Ident,
|
||||
smtpHost: String,
|
||||
smtpPort: Option[Int],
|
||||
smtpUser: Option[String],
|
||||
smtpPassword: Option[Password],
|
||||
smtpSsl: SSLType,
|
||||
smtpCertCheck: Boolean,
|
||||
mailFrom: MailAddress,
|
||||
mailReplyTo: Option[MailAddress]
|
||||
): F[RUserEmail] =
|
||||
for {
|
||||
now <- Timestamp.current[F]
|
||||
id <- Ident.randomId[F]
|
||||
} yield RUserEmail(
|
||||
id,
|
||||
uid,
|
||||
name,
|
||||
smtpHost,
|
||||
smtpPort,
|
||||
smtpUser,
|
||||
smtpPassword,
|
||||
smtpSsl,
|
||||
smtpCertCheck,
|
||||
mailFrom,
|
||||
mailReplyTo,
|
||||
now
|
||||
)
|
||||
|
||||
def apply(
|
||||
accId: AccountId,
|
||||
name: Ident,
|
||||
smtpHost: String,
|
||||
smtpPort: Option[Int],
|
||||
smtpUser: Option[String],
|
||||
smtpPassword: Option[Password],
|
||||
smtpSsl: SSLType,
|
||||
smtpCertCheck: Boolean,
|
||||
mailFrom: MailAddress,
|
||||
mailReplyTo: Option[MailAddress]
|
||||
): OptionT[ConnectionIO, RUserEmail] =
|
||||
for {
|
||||
now <- OptionT.liftF(Timestamp.current[ConnectionIO])
|
||||
id <- OptionT.liftF(Ident.randomId[ConnectionIO])
|
||||
user <- OptionT(RUser.findByAccount(accId))
|
||||
} yield RUserEmail(
|
||||
id,
|
||||
user.uid,
|
||||
name,
|
||||
smtpHost,
|
||||
smtpPort,
|
||||
smtpUser,
|
||||
smtpPassword,
|
||||
smtpSsl,
|
||||
smtpCertCheck,
|
||||
mailFrom,
|
||||
mailReplyTo,
|
||||
now
|
||||
)
|
||||
|
||||
val table = fr"useremail"
|
||||
|
||||
object Columns {
|
||||
@ -65,7 +129,54 @@ object RUserEmail {
|
||||
sql"${v.id},${v.uid},${v.name},${v.smtpHost},${v.smtpPort},${v.smtpUser},${v.smtpPassword},${v.smtpSsl},${v.smtpCertCheck},${v.mailFrom},${v.mailReplyTo},${v.created}"
|
||||
).update.run
|
||||
|
||||
def update(eId: Ident, v: RUserEmail): ConnectionIO[Int] =
|
||||
updateRow(table, id.is(eId), commas(
|
||||
name.setTo(v.name),
|
||||
smtpHost.setTo(v.smtpHost),
|
||||
smtpPort.setTo(v.smtpPort),
|
||||
smtpUser.setTo(v.smtpUser),
|
||||
smtpPass.setTo(v.smtpPassword),
|
||||
smtpSsl.setTo(v.smtpSsl),
|
||||
smtpCertCheck.setTo(v.smtpCertCheck),
|
||||
mailFrom.setTo(v.mailFrom),
|
||||
mailReplyTo.setTo(v.mailReplyTo)
|
||||
)).update.run
|
||||
|
||||
def findByUser(userId: Ident): ConnectionIO[Vector[RUserEmail]] =
|
||||
selectSimple(all, table, uid.is(userId)).query[RUserEmail].to[Vector]
|
||||
|
||||
private def findByAccount0(
|
||||
accId: AccountId,
|
||||
nameQ: Option[String],
|
||||
exact: Boolean
|
||||
): Query0[RUserEmail] = {
|
||||
val mUid = uid.prefix("m")
|
||||
val mName = name.prefix("m")
|
||||
val uId = RUser.Columns.uid.prefix("u")
|
||||
val uColl = RUser.Columns.cid.prefix("u")
|
||||
val uLogin = RUser.Columns.login.prefix("u")
|
||||
val from = table ++ fr"m INNER JOIN" ++ RUser.table ++ fr"u ON" ++ mUid.is(uId)
|
||||
val cond = Seq(uColl.is(accId.collective), uLogin.is(accId.user)) ++ (nameQ match {
|
||||
case Some(str) if exact => Seq(mName.is(str))
|
||||
case Some(str) if !exact => Seq(mName.lowerLike(s"%${str.toLowerCase}%"))
|
||||
case None => Seq.empty
|
||||
})
|
||||
|
||||
selectSimple(all, from, and(cond)).query[RUserEmail]
|
||||
}
|
||||
|
||||
def findByAccount(
|
||||
accId: AccountId,
|
||||
nameQ: Option[String]
|
||||
): ConnectionIO[Vector[RUserEmail]] =
|
||||
findByAccount0(accId, nameQ, false).to[Vector]
|
||||
|
||||
def getByName(accId: AccountId, name: Ident): ConnectionIO[Option[RUserEmail]] =
|
||||
findByAccount0(accId, Some(name.id), true).option
|
||||
|
||||
def exists(accId: AccountId, name: Ident): ConnectionIO[Boolean] =
|
||||
getByName(accId, name).map(_.isDefined)
|
||||
|
||||
def exists(userId: Ident, connName: Ident): ConnectionIO[Boolean] =
|
||||
selectCount(id, table, and(uid.is(userId), name.is(connName))).query[Int].unique.map(_ > 0)
|
||||
}
|
||||
|
Reference in New Issue
Block a user