mirror of
				https://github.com/TheAnachronism/docspell.git
				synced 2025-11-03 18:00:11 +00:00 
			
		
		
		
	Finish mail settings
This commit is contained in:
		@@ -3,6 +3,8 @@ package docspell.backend.ops
 | 
				
			|||||||
import cats.effect._
 | 
					import cats.effect._
 | 
				
			||||||
import cats.implicits._
 | 
					import cats.implicits._
 | 
				
			||||||
import cats.data.OptionT
 | 
					import cats.data.OptionT
 | 
				
			||||||
 | 
					import emil.{MailAddress, SSLType}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import docspell.common._
 | 
					import docspell.common._
 | 
				
			||||||
import docspell.store._
 | 
					import docspell.store._
 | 
				
			||||||
import docspell.store.records.RUserEmail
 | 
					import docspell.store.records.RUserEmail
 | 
				
			||||||
@@ -11,33 +13,71 @@ trait OMail[F[_]] {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  def getSettings(accId: AccountId, nameQ: Option[String]): F[Vector[RUserEmail]]
 | 
					  def getSettings(accId: AccountId, nameQ: Option[String]): F[Vector[RUserEmail]]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def createSettings(data: F[RUserEmail]): F[AddResult]
 | 
					  def findSettings(accId: AccountId, name: Ident): OptionT[F, RUserEmail]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def updateSettings(accId: AccountId, name: Ident, data: RUserEmail): F[Int]
 | 
					  def createSettings(accId: AccountId, data: OMail.SmtpSettings): F[AddResult]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def updateSettings(accId: AccountId, name: Ident, data: OMail.SmtpSettings): F[Int]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def deleteSettings(accId: AccountId, name: Ident): F[Int]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
object OMail {
 | 
					object OMail {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  case class SmtpSettings(
 | 
				
			||||||
 | 
					      name: Ident,
 | 
				
			||||||
 | 
					      smtpHost: String,
 | 
				
			||||||
 | 
					      smtpPort: Option[Int],
 | 
				
			||||||
 | 
					      smtpUser: Option[String],
 | 
				
			||||||
 | 
					      smtpPassword: Option[Password],
 | 
				
			||||||
 | 
					      smtpSsl: SSLType,
 | 
				
			||||||
 | 
					      smtpCertCheck: Boolean,
 | 
				
			||||||
 | 
					      mailFrom: MailAddress,
 | 
				
			||||||
 | 
					      mailReplyTo: Option[MailAddress]
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def toRecord(accId: AccountId) =
 | 
				
			||||||
 | 
					      RUserEmail.fromAccount(
 | 
				
			||||||
 | 
					        accId,
 | 
				
			||||||
 | 
					        name,
 | 
				
			||||||
 | 
					        smtpHost,
 | 
				
			||||||
 | 
					        smtpPort,
 | 
				
			||||||
 | 
					        smtpUser,
 | 
				
			||||||
 | 
					        smtpPassword,
 | 
				
			||||||
 | 
					        smtpSsl,
 | 
				
			||||||
 | 
					        smtpCertCheck,
 | 
				
			||||||
 | 
					        mailFrom,
 | 
				
			||||||
 | 
					        mailReplyTo
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def apply[F[_]: Effect](store: Store[F]): Resource[F, OMail[F]] =
 | 
					  def apply[F[_]: Effect](store: Store[F]): Resource[F, OMail[F]] =
 | 
				
			||||||
    Resource.pure(new OMail[F] {
 | 
					    Resource.pure(new OMail[F] {
 | 
				
			||||||
      def getSettings(accId: AccountId, nameQ: Option[String]): F[Vector[RUserEmail]] =
 | 
					      def getSettings(accId: AccountId, nameQ: Option[String]): F[Vector[RUserEmail]] =
 | 
				
			||||||
        store.transact(RUserEmail.findByAccount(accId, nameQ))
 | 
					        store.transact(RUserEmail.findByAccount(accId, nameQ))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      def createSettings(data: F[RUserEmail]): F[AddResult] =
 | 
					      def findSettings(accId: AccountId, name: Ident): OptionT[F, RUserEmail] =
 | 
				
			||||||
        for {
 | 
					        OptionT(store.transact(RUserEmail.getByName(accId, name)))
 | 
				
			||||||
          ru <- data
 | 
					 | 
				
			||||||
          ins = RUserEmail.insert(ru)
 | 
					 | 
				
			||||||
          exists = RUserEmail.exists(ru.uid, ru.name)
 | 
					 | 
				
			||||||
          ar <- store.add(ins, exists)
 | 
					 | 
				
			||||||
        } yield ar
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      def updateSettings(accId: AccountId, name: Ident, data: RUserEmail): F[Int] = {
 | 
					      def createSettings(accId: AccountId, s: SmtpSettings): F[AddResult] =
 | 
				
			||||||
 | 
					        (for {
 | 
				
			||||||
 | 
					          ru <- OptionT(store.transact(s.toRecord(accId).value))
 | 
				
			||||||
 | 
					          ins    = RUserEmail.insert(ru)
 | 
				
			||||||
 | 
					          exists = RUserEmail.exists(ru.uid, ru.name)
 | 
				
			||||||
 | 
					          res <- OptionT.liftF(store.add(ins, exists))
 | 
				
			||||||
 | 
					        } yield res).getOrElse(AddResult.Failure(new Exception("User not found")))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      def updateSettings(accId: AccountId, name: Ident, data: SmtpSettings): F[Int] = {
 | 
				
			||||||
        val op = for {
 | 
					        val op = for {
 | 
				
			||||||
          um <- OptionT(RUserEmail.getByName(accId, name))
 | 
					          um <- OptionT(RUserEmail.getByName(accId, name))
 | 
				
			||||||
          n  <- OptionT.liftF(RUserEmail.update(um.id, data))
 | 
					          ru <- data.toRecord(accId)
 | 
				
			||||||
 | 
					          n  <- OptionT.liftF(RUserEmail.update(um.id, ru))
 | 
				
			||||||
        } yield n
 | 
					        } yield n
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        store.transact(op.value).map(_.getOrElse(0))
 | 
					        store.transact(op.value).map(_.getOrElse(0))
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      def deleteSettings(accId: AccountId, name: Ident): F[Int] =
 | 
				
			||||||
 | 
					        store.transact(RUserEmail.delete(accId, name))
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,17 +2,21 @@ package docspell.restserver.routes
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import cats.effect._
 | 
					import cats.effect._
 | 
				
			||||||
import cats.implicits._
 | 
					import cats.implicits._
 | 
				
			||||||
 | 
					import cats.data.OptionT
 | 
				
			||||||
import org.http4s._
 | 
					import org.http4s._
 | 
				
			||||||
import org.http4s.dsl.Http4sDsl
 | 
					import org.http4s.dsl.Http4sDsl
 | 
				
			||||||
import org.http4s.circe.CirceEntityEncoder._
 | 
					import org.http4s.circe.CirceEntityEncoder._
 | 
				
			||||||
import org.http4s.circe.CirceEntityDecoder._
 | 
					import org.http4s.circe.CirceEntityDecoder._
 | 
				
			||||||
 | 
					import emil.MailAddress
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import docspell.backend.BackendApp
 | 
					import docspell.backend.BackendApp
 | 
				
			||||||
import docspell.backend.auth.AuthToken
 | 
					import docspell.backend.auth.AuthToken
 | 
				
			||||||
 | 
					import docspell.backend.ops.OMail
 | 
				
			||||||
import docspell.common._
 | 
					import docspell.common._
 | 
				
			||||||
import docspell.restapi.model._
 | 
					import docspell.restapi.model._
 | 
				
			||||||
import docspell.store.records.RUserEmail
 | 
					import docspell.store.records.RUserEmail
 | 
				
			||||||
import docspell.store.EmilUtil
 | 
					import docspell.store.EmilUtil
 | 
				
			||||||
 | 
					import docspell.restserver.conv.Conversions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
object MailSettingsRoutes {
 | 
					object MailSettingsRoutes {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,10 +33,51 @@ object MailSettingsRoutes {
 | 
				
			|||||||
          resp <- Ok(EmailSettingsList(res.toList))
 | 
					          resp <- Ok(EmailSettingsList(res.toList))
 | 
				
			||||||
        } yield resp
 | 
					        } yield resp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      case GET -> Root / Ident(name) =>
 | 
				
			||||||
 | 
					        (for {
 | 
				
			||||||
 | 
					          ems  <- backend.mail.findSettings(user.account, name)
 | 
				
			||||||
 | 
					          resp <- OptionT.liftF(Ok(convert(ems)))
 | 
				
			||||||
 | 
					        } yield resp).getOrElseF(NotFound())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      case req @ POST -> Root =>
 | 
					      case req @ POST -> Root =>
 | 
				
			||||||
 | 
					        (for {
 | 
				
			||||||
 | 
					          in <- OptionT.liftF(req.as[EmailSettings])
 | 
				
			||||||
 | 
					          ru = makeSettings(in)
 | 
				
			||||||
 | 
					          up <- OptionT.liftF(ru.traverse(r => backend.mail.createSettings(user.account, r)))
 | 
				
			||||||
 | 
					          resp <- OptionT.liftF(
 | 
				
			||||||
 | 
					            Ok(
 | 
				
			||||||
 | 
					              up.fold(
 | 
				
			||||||
 | 
					                err => BasicResult(false, err),
 | 
				
			||||||
 | 
					                ar => Conversions.basicResult(ar, "Mail settings stored.")
 | 
				
			||||||
 | 
					              )
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					        } yield resp).getOrElseF(NotFound())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      case req @ PUT -> Root / Ident(name) =>
 | 
				
			||||||
 | 
					        (for {
 | 
				
			||||||
 | 
					          in <- OptionT.liftF(req.as[EmailSettings])
 | 
				
			||||||
 | 
					          ru = makeSettings(in)
 | 
				
			||||||
 | 
					          up <- OptionT.liftF(ru.traverse(r => backend.mail.updateSettings(user.account, name, r)))
 | 
				
			||||||
 | 
					          resp <- OptionT.liftF(
 | 
				
			||||||
 | 
					            Ok(
 | 
				
			||||||
 | 
					              up.fold(
 | 
				
			||||||
 | 
					                err => BasicResult(false, err),
 | 
				
			||||||
 | 
					                n =>
 | 
				
			||||||
 | 
					                  if (n > 0) BasicResult(true, "Mail settings stored.")
 | 
				
			||||||
 | 
					                  else BasicResult(false, "Mail settings could not be saved")
 | 
				
			||||||
 | 
					              )
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					        } yield resp).getOrElseF(NotFound())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      case DELETE -> Root / Ident(name) =>
 | 
				
			||||||
        for {
 | 
					        for {
 | 
				
			||||||
          in   <- req.as[EmailSettings]
 | 
					          n <- backend.mail.deleteSettings(user.account, name)
 | 
				
			||||||
          resp <- Ok(BasicResult(false, "not implemented"))
 | 
					          resp <- Ok(
 | 
				
			||||||
 | 
					            if (n > 0) BasicResult(true, "Mail settings removed")
 | 
				
			||||||
 | 
					            else BasicResult(false, "Mail settings could not be removed")
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
        } yield resp
 | 
					        } yield resp
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -50,4 +95,29 @@ object MailSettingsRoutes {
 | 
				
			|||||||
      EmilUtil.sslTypeString(ru.smtpSsl),
 | 
					      EmilUtil.sslTypeString(ru.smtpSsl),
 | 
				
			||||||
      !ru.smtpCertCheck
 | 
					      !ru.smtpCertCheck
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def makeSettings(ems: EmailSettings): Either[String, OMail.SmtpSettings] = {
 | 
				
			||||||
 | 
					    def readMail(str: String): Either[String, MailAddress] =
 | 
				
			||||||
 | 
					      EmilUtil.readMailAddress(str).left.map(err => s"E-Mail address '$str' invalid: $err")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def readMailOpt(str: Option[String]): Either[String, Option[MailAddress]] =
 | 
				
			||||||
 | 
					      str.traverse(readMail)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for {
 | 
				
			||||||
 | 
					      from <- readMail(ems.from)
 | 
				
			||||||
 | 
					      repl <- readMailOpt(ems.replyTo)
 | 
				
			||||||
 | 
					      sslt <- EmilUtil.readSSLType(ems.sslType)
 | 
				
			||||||
 | 
					    } yield OMail.SmtpSettings(
 | 
				
			||||||
 | 
					      ems.name,
 | 
				
			||||||
 | 
					      ems.smtpHost,
 | 
				
			||||||
 | 
					      ems.smtpPort,
 | 
				
			||||||
 | 
					      ems.smtpUser,
 | 
				
			||||||
 | 
					      ems.smtpPassword,
 | 
				
			||||||
 | 
					      sslt,
 | 
				
			||||||
 | 
					      !ems.ignoreCertificates,
 | 
				
			||||||
 | 
					      from,
 | 
				
			||||||
 | 
					      repl
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,9 +3,9 @@ CREATE TABLE "useremail" (
 | 
				
			|||||||
  "uid" varchar(254) not null,
 | 
					  "uid" varchar(254) not null,
 | 
				
			||||||
  "name" varchar(254) not null,
 | 
					  "name" varchar(254) not null,
 | 
				
			||||||
  "smtp_host" varchar(254) not null,
 | 
					  "smtp_host" varchar(254) not null,
 | 
				
			||||||
  "smtp_port" int not null,
 | 
					  "smtp_port" int,
 | 
				
			||||||
  "smtp_user" varchar(254) not null,
 | 
					  "smtp_user" varchar(254),
 | 
				
			||||||
  "smtp_password" varchar(254) not null,
 | 
					  "smtp_password" varchar(254),
 | 
				
			||||||
  "smtp_ssl" varchar(254) not null,
 | 
					  "smtp_ssl" varchar(254) not null,
 | 
				
			||||||
  "smtp_certcheck" boolean not null,
 | 
					  "smtp_certcheck" boolean not null,
 | 
				
			||||||
  "mail_from" varchar(254) not null,
 | 
					  "mail_from" varchar(254) not null,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,7 +57,7 @@ object RUserEmail {
 | 
				
			|||||||
      now
 | 
					      now
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def apply(
 | 
					  def fromAccount(
 | 
				
			||||||
      accId: AccountId,
 | 
					      accId: AccountId,
 | 
				
			||||||
      name: Ident,
 | 
					      name: Ident,
 | 
				
			||||||
      smtpHost: String,
 | 
					      smtpHost: String,
 | 
				
			||||||
@@ -130,17 +130,21 @@ object RUserEmail {
 | 
				
			|||||||
    ).update.run
 | 
					    ).update.run
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def update(eId: Ident, v: RUserEmail): ConnectionIO[Int] =
 | 
					  def update(eId: Ident, v: RUserEmail): ConnectionIO[Int] =
 | 
				
			||||||
    updateRow(table, id.is(eId), commas(
 | 
					    updateRow(
 | 
				
			||||||
      name.setTo(v.name),
 | 
					      table,
 | 
				
			||||||
      smtpHost.setTo(v.smtpHost),
 | 
					      id.is(eId),
 | 
				
			||||||
      smtpPort.setTo(v.smtpPort),
 | 
					      commas(
 | 
				
			||||||
      smtpUser.setTo(v.smtpUser),
 | 
					        name.setTo(v.name),
 | 
				
			||||||
      smtpPass.setTo(v.smtpPassword),
 | 
					        smtpHost.setTo(v.smtpHost),
 | 
				
			||||||
      smtpSsl.setTo(v.smtpSsl),
 | 
					        smtpPort.setTo(v.smtpPort),
 | 
				
			||||||
      smtpCertCheck.setTo(v.smtpCertCheck),
 | 
					        smtpUser.setTo(v.smtpUser),
 | 
				
			||||||
      mailFrom.setTo(v.mailFrom),
 | 
					        smtpPass.setTo(v.smtpPassword),
 | 
				
			||||||
      mailReplyTo.setTo(v.mailReplyTo)
 | 
					        smtpSsl.setTo(v.smtpSsl),
 | 
				
			||||||
    )).update.run
 | 
					        smtpCertCheck.setTo(v.smtpCertCheck),
 | 
				
			||||||
 | 
					        mailFrom.setTo(v.mailFrom),
 | 
				
			||||||
 | 
					        mailReplyTo.setTo(v.mailReplyTo)
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    ).update.run
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def findByUser(userId: Ident): ConnectionIO[Vector[RUserEmail]] =
 | 
					  def findByUser(userId: Ident): ConnectionIO[Vector[RUserEmail]] =
 | 
				
			||||||
    selectSimple(all, table, uid.is(userId)).query[RUserEmail].to[Vector]
 | 
					    selectSimple(all, table, uid.is(userId)).query[RUserEmail].to[Vector]
 | 
				
			||||||
@@ -162,7 +166,7 @@ object RUserEmail {
 | 
				
			|||||||
      case None                => Seq.empty
 | 
					      case None                => Seq.empty
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    selectSimple(all, from, and(cond)).query[RUserEmail]
 | 
					    (selectSimple(all.map(_.prefix("m")), from, and(cond)) ++ orderBy(mName.f)).query[RUserEmail]
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def findByAccount(
 | 
					  def findByAccount(
 | 
				
			||||||
@@ -174,6 +178,20 @@ object RUserEmail {
 | 
				
			|||||||
  def getByName(accId: AccountId, name: Ident): ConnectionIO[Option[RUserEmail]] =
 | 
					  def getByName(accId: AccountId, name: Ident): ConnectionIO[Option[RUserEmail]] =
 | 
				
			||||||
    findByAccount0(accId, Some(name.id), true).option
 | 
					    findByAccount0(accId, Some(name.id), true).option
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def delete(accId: AccountId, connName: Ident): ConnectionIO[Int] = {
 | 
				
			||||||
 | 
					    val uId    = RUser.Columns.uid
 | 
				
			||||||
 | 
					    val uColl  = RUser.Columns.cid
 | 
				
			||||||
 | 
					    val uLogin = RUser.Columns.login
 | 
				
			||||||
 | 
					    val cond   = Seq(uColl.is(accId.collective), uLogin.is(accId.user))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    deleteFrom(
 | 
				
			||||||
 | 
					      table,
 | 
				
			||||||
 | 
					      fr"uid in (" ++ selectSimple(Seq(uId), RUser.table, and(cond)) ++ fr") AND" ++ name.is(
 | 
				
			||||||
 | 
					        connName
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    ).update.run
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def exists(accId: AccountId, name: Ident): ConnectionIO[Boolean] =
 | 
					  def exists(accId: AccountId, name: Ident): ConnectionIO[Boolean] =
 | 
				
			||||||
    getByName(accId, name).map(_.isDefined)
 | 
					    getByName(accId, name).map(_.isDefined)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,10 @@
 | 
				
			|||||||
module Api exposing
 | 
					module Api exposing
 | 
				
			||||||
    ( cancelJob
 | 
					    ( cancelJob
 | 
				
			||||||
    , changePassword
 | 
					    , changePassword
 | 
				
			||||||
 | 
					    , createMailSettings
 | 
				
			||||||
    , deleteEquip
 | 
					    , deleteEquip
 | 
				
			||||||
    , deleteItem
 | 
					    , deleteItem
 | 
				
			||||||
 | 
					    , deleteMailSettings
 | 
				
			||||||
    , deleteOrg
 | 
					    , deleteOrg
 | 
				
			||||||
    , deletePerson
 | 
					    , deletePerson
 | 
				
			||||||
    , deleteSource
 | 
					    , deleteSource
 | 
				
			||||||
@@ -15,6 +17,7 @@ module Api exposing
 | 
				
			|||||||
    , getItemProposals
 | 
					    , getItemProposals
 | 
				
			||||||
    , getJobQueueState
 | 
					    , getJobQueueState
 | 
				
			||||||
    , getJobQueueStateIn
 | 
					    , getJobQueueStateIn
 | 
				
			||||||
 | 
					    , getMailSettings
 | 
				
			||||||
    , getOrgLight
 | 
					    , getOrgLight
 | 
				
			||||||
    , getOrganizations
 | 
					    , getOrganizations
 | 
				
			||||||
    , getPersons
 | 
					    , getPersons
 | 
				
			||||||
@@ -60,6 +63,8 @@ import Api.Model.BasicResult exposing (BasicResult)
 | 
				
			|||||||
import Api.Model.Collective exposing (Collective)
 | 
					import Api.Model.Collective exposing (Collective)
 | 
				
			||||||
import Api.Model.CollectiveSettings exposing (CollectiveSettings)
 | 
					import Api.Model.CollectiveSettings exposing (CollectiveSettings)
 | 
				
			||||||
import Api.Model.DirectionValue exposing (DirectionValue)
 | 
					import Api.Model.DirectionValue exposing (DirectionValue)
 | 
				
			||||||
 | 
					import Api.Model.EmailSettings exposing (EmailSettings)
 | 
				
			||||||
 | 
					import Api.Model.EmailSettingsList exposing (EmailSettingsList)
 | 
				
			||||||
import Api.Model.Equipment exposing (Equipment)
 | 
					import Api.Model.Equipment exposing (Equipment)
 | 
				
			||||||
import Api.Model.EquipmentList exposing (EquipmentList)
 | 
					import Api.Model.EquipmentList exposing (EquipmentList)
 | 
				
			||||||
import Api.Model.GenInvite exposing (GenInvite)
 | 
					import Api.Model.GenInvite exposing (GenInvite)
 | 
				
			||||||
@@ -99,6 +104,57 @@ import Util.File
 | 
				
			|||||||
import Util.Http as Http2
 | 
					import Util.Http as Http2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--- Mail Settings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					deleteMailSettings : Flags -> String -> (Result Http.Error BasicResult -> msg) -> Cmd msg
 | 
				
			||||||
 | 
					deleteMailSettings flags name receive =
 | 
				
			||||||
 | 
					    Http2.authDelete
 | 
				
			||||||
 | 
					        { url = flags.config.baseUrl ++ "/api/v1/sec/email/settings/" ++ name
 | 
				
			||||||
 | 
					        , account = getAccount flags
 | 
				
			||||||
 | 
					        , expect = Http.expectJson receive Api.Model.BasicResult.decoder
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					getMailSettings : Flags -> String -> (Result Http.Error EmailSettingsList -> msg) -> Cmd msg
 | 
				
			||||||
 | 
					getMailSettings flags query receive =
 | 
				
			||||||
 | 
					    Http2.authGet
 | 
				
			||||||
 | 
					        { url = flags.config.baseUrl ++ "/api/v1/sec/email/settings?q=" ++ Url.percentEncode query
 | 
				
			||||||
 | 
					        , account = getAccount flags
 | 
				
			||||||
 | 
					        , expect = Http.expectJson receive Api.Model.EmailSettingsList.decoder
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					createMailSettings :
 | 
				
			||||||
 | 
					    Flags
 | 
				
			||||||
 | 
					    -> Maybe String
 | 
				
			||||||
 | 
					    -> EmailSettings
 | 
				
			||||||
 | 
					    -> (Result Http.Error BasicResult -> msg)
 | 
				
			||||||
 | 
					    -> Cmd msg
 | 
				
			||||||
 | 
					createMailSettings flags mname ems receive =
 | 
				
			||||||
 | 
					    case mname of
 | 
				
			||||||
 | 
					        Just en ->
 | 
				
			||||||
 | 
					            Http2.authPut
 | 
				
			||||||
 | 
					                { url = flags.config.baseUrl ++ "/api/v1/sec/email/settings/" ++ en
 | 
				
			||||||
 | 
					                , account = getAccount flags
 | 
				
			||||||
 | 
					                , body = Http.jsonBody (Api.Model.EmailSettings.encode ems)
 | 
				
			||||||
 | 
					                , expect = Http.expectJson receive Api.Model.BasicResult.decoder
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Nothing ->
 | 
				
			||||||
 | 
					            Http2.authPost
 | 
				
			||||||
 | 
					                { url = flags.config.baseUrl ++ "/api/v1/sec/email/settings"
 | 
				
			||||||
 | 
					                , account = getAccount flags
 | 
				
			||||||
 | 
					                , body = Http.jsonBody (Api.Model.EmailSettings.encode ems)
 | 
				
			||||||
 | 
					                , expect = Http.expectJson receive Api.Model.BasicResult.decoder
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--- Upload
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
upload : Flags -> Maybe String -> ItemUploadMeta -> List File -> (String -> Result Http.Error BasicResult -> msg) -> List (Cmd msg)
 | 
					upload : Flags -> Maybe String -> ItemUploadMeta -> List File -> (String -> Result Http.Error BasicResult -> msg) -> List (Cmd msg)
 | 
				
			||||||
upload flags sourceId meta files receive =
 | 
					upload flags sourceId meta files receive =
 | 
				
			||||||
    let
 | 
					    let
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ module Comp.EmailSettingsForm exposing
 | 
				
			|||||||
    , emptyModel
 | 
					    , emptyModel
 | 
				
			||||||
    , getSettings
 | 
					    , getSettings
 | 
				
			||||||
    , init
 | 
					    , init
 | 
				
			||||||
 | 
					    , isValid
 | 
				
			||||||
    , update
 | 
					    , update
 | 
				
			||||||
    , view
 | 
					    , view
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
@@ -40,7 +41,7 @@ emptyModel =
 | 
				
			|||||||
    { settings = Api.Model.EmailSettings.empty
 | 
					    { settings = Api.Model.EmailSettings.empty
 | 
				
			||||||
    , name = ""
 | 
					    , name = ""
 | 
				
			||||||
    , host = ""
 | 
					    , host = ""
 | 
				
			||||||
    , portField = Comp.IntField.init (Just 0) Nothing "SMTP Port"
 | 
					    , portField = Comp.IntField.init (Just 0) Nothing True "SMTP Port"
 | 
				
			||||||
    , portNum = Nothing
 | 
					    , portNum = Nothing
 | 
				
			||||||
    , user = Nothing
 | 
					    , user = Nothing
 | 
				
			||||||
    , passField = Comp.PasswordInput.init
 | 
					    , passField = Comp.PasswordInput.init
 | 
				
			||||||
@@ -63,7 +64,7 @@ init ems =
 | 
				
			|||||||
    { settings = ems
 | 
					    { settings = ems
 | 
				
			||||||
    , name = ems.name
 | 
					    , name = ems.name
 | 
				
			||||||
    , host = ems.smtpHost
 | 
					    , host = ems.smtpHost
 | 
				
			||||||
    , portField = Comp.IntField.init (Just 0) Nothing "SMTP Port"
 | 
					    , portField = Comp.IntField.init (Just 0) Nothing True "SMTP Port"
 | 
				
			||||||
    , portNum = ems.smtpPort
 | 
					    , portNum = ems.smtpPort
 | 
				
			||||||
    , user = ems.smtpUser
 | 
					    , user = ems.smtpUser
 | 
				
			||||||
    , passField = Comp.PasswordInput.init
 | 
					    , passField = Comp.PasswordInput.init
 | 
				
			||||||
@@ -184,7 +185,7 @@ view model =
 | 
				
			|||||||
                ]
 | 
					                ]
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        , div [ class "fields" ]
 | 
					        , div [ class "fields" ]
 | 
				
			||||||
            [ div [ class "fifteen wide required field" ]
 | 
					            [ div [ class "thirteen wide required field" ]
 | 
				
			||||||
                [ label [] [ text "SMTP Host" ]
 | 
					                [ label [] [ text "SMTP Host" ]
 | 
				
			||||||
                , input
 | 
					                , input
 | 
				
			||||||
                    [ type_ "text"
 | 
					                    [ type_ "text"
 | 
				
			||||||
@@ -194,7 +195,11 @@ view model =
 | 
				
			|||||||
                    ]
 | 
					                    ]
 | 
				
			||||||
                    []
 | 
					                    []
 | 
				
			||||||
                ]
 | 
					                ]
 | 
				
			||||||
            , Html.map PortMsg (Comp.IntField.view model.portNum model.portField)
 | 
					            , Html.map PortMsg
 | 
				
			||||||
 | 
					                (Comp.IntField.view model.portNum
 | 
				
			||||||
 | 
					                    "three wide field"
 | 
				
			||||||
 | 
					                    model.portField
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        , div [ class "two fields" ]
 | 
					        , div [ class "two fields" ]
 | 
				
			||||||
            [ div [ class "field" ]
 | 
					            [ div [ class "field" ]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,8 @@ import Data.Flags exposing (Flags)
 | 
				
			|||||||
import Html exposing (..)
 | 
					import Html exposing (..)
 | 
				
			||||||
import Html.Attributes exposing (..)
 | 
					import Html.Attributes exposing (..)
 | 
				
			||||||
import Html.Events exposing (onClick, onInput)
 | 
					import Html.Events exposing (onClick, onInput)
 | 
				
			||||||
 | 
					import Http
 | 
				
			||||||
 | 
					import Util.Http
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type alias Model =
 | 
					type alias Model =
 | 
				
			||||||
@@ -43,9 +45,9 @@ emptyModel =
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
init : ( Model, Cmd Msg )
 | 
					init : Flags -> ( Model, Cmd Msg )
 | 
				
			||||||
init =
 | 
					init flags =
 | 
				
			||||||
    ( emptyModel, Cmd.none )
 | 
					    ( emptyModel, Api.getMailSettings flags "" MailSettingsResp )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ViewMode
 | 
					type ViewMode
 | 
				
			||||||
@@ -61,6 +63,10 @@ type Msg
 | 
				
			|||||||
    | YesNoMsg Comp.YesNoDimmer.Msg
 | 
					    | YesNoMsg Comp.YesNoDimmer.Msg
 | 
				
			||||||
    | RequestDelete
 | 
					    | RequestDelete
 | 
				
			||||||
    | SetViewMode ViewMode
 | 
					    | SetViewMode ViewMode
 | 
				
			||||||
 | 
					    | Submit
 | 
				
			||||||
 | 
					    | SubmitResp (Result Http.Error BasicResult)
 | 
				
			||||||
 | 
					    | LoadSettings
 | 
				
			||||||
 | 
					    | MailSettingsResp (Result Http.Error EmailSettingsList)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
 | 
					update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
 | 
				
			||||||
@@ -84,8 +90,27 @@ update flags msg model =
 | 
				
			|||||||
            let
 | 
					            let
 | 
				
			||||||
                ( tm, tc ) =
 | 
					                ( tm, tc ) =
 | 
				
			||||||
                    Comp.EmailSettingsTable.update m model.tableModel
 | 
					                    Comp.EmailSettingsTable.update m model.tableModel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                m2 =
 | 
				
			||||||
 | 
					                    { model
 | 
				
			||||||
 | 
					                        | tableModel = tm
 | 
				
			||||||
 | 
					                        , viewMode = Maybe.map (\_ -> Form) tm.selected |> Maybe.withDefault Table
 | 
				
			||||||
 | 
					                        , formError =
 | 
				
			||||||
 | 
					                            if tm.selected /= Nothing then
 | 
				
			||||||
 | 
					                                Nothing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            else
 | 
				
			||||||
 | 
					                                model.formError
 | 
				
			||||||
 | 
					                        , formModel =
 | 
				
			||||||
 | 
					                            case tm.selected of
 | 
				
			||||||
 | 
					                                Just ems ->
 | 
				
			||||||
 | 
					                                    Comp.EmailSettingsForm.init ems
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                Nothing ->
 | 
				
			||||||
 | 
					                                    model.formModel
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
            in
 | 
					            in
 | 
				
			||||||
            ( { model | tableModel = tm }, Cmd.map TableMsg tc )
 | 
					            ( m2, Cmd.map TableMsg tc )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        FormMsg m ->
 | 
					        FormMsg m ->
 | 
				
			||||||
            let
 | 
					            let
 | 
				
			||||||
@@ -95,21 +120,84 @@ update flags msg model =
 | 
				
			|||||||
            ( { model | formModel = fm }, Cmd.map FormMsg fc )
 | 
					            ( { model | formModel = fm }, Cmd.map FormMsg fc )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SetQuery str ->
 | 
					        SetQuery str ->
 | 
				
			||||||
            ( { model | query = str }, Cmd.none )
 | 
					            let
 | 
				
			||||||
 | 
					                m =
 | 
				
			||||||
 | 
					                    { model | query = str }
 | 
				
			||||||
 | 
					            in
 | 
				
			||||||
 | 
					            ( m, Api.getMailSettings flags str MailSettingsResp )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        YesNoMsg m ->
 | 
					        YesNoMsg m ->
 | 
				
			||||||
            let
 | 
					            let
 | 
				
			||||||
                ( dm, flag ) =
 | 
					                ( dm, flag ) =
 | 
				
			||||||
                    Comp.YesNoDimmer.update m model.deleteConfirm
 | 
					                    Comp.YesNoDimmer.update m model.deleteConfirm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                ( mid, _ ) =
 | 
				
			||||||
 | 
					                    Comp.EmailSettingsForm.getSettings model.formModel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                cmd =
 | 
				
			||||||
 | 
					                    case ( flag, mid ) of
 | 
				
			||||||
 | 
					                        ( True, Just name ) ->
 | 
				
			||||||
 | 
					                            Api.deleteMailSettings flags name SubmitResp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        _ ->
 | 
				
			||||||
 | 
					                            Cmd.none
 | 
				
			||||||
            in
 | 
					            in
 | 
				
			||||||
            ( { model | deleteConfirm = dm }, Cmd.none )
 | 
					            ( { model | deleteConfirm = dm }, cmd )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        RequestDelete ->
 | 
					        RequestDelete ->
 | 
				
			||||||
            ( model, Cmd.none )
 | 
					            update flags (YesNoMsg Comp.YesNoDimmer.activate) model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SetViewMode m ->
 | 
					        SetViewMode m ->
 | 
				
			||||||
            ( { model | viewMode = m }, Cmd.none )
 | 
					            ( { model | viewMode = m }, Cmd.none )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Submit ->
 | 
				
			||||||
 | 
					            let
 | 
				
			||||||
 | 
					                ( mid, ems ) =
 | 
				
			||||||
 | 
					                    Comp.EmailSettingsForm.getSettings model.formModel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                valid =
 | 
				
			||||||
 | 
					                    Comp.EmailSettingsForm.isValid model.formModel
 | 
				
			||||||
 | 
					            in
 | 
				
			||||||
 | 
					            if valid then
 | 
				
			||||||
 | 
					                ( { model | loading = True }, Api.createMailSettings flags mid ems SubmitResp )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                ( { model | formError = Just "Please fill required fields." }, Cmd.none )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        LoadSettings ->
 | 
				
			||||||
 | 
					            ( { model | loading = True }, Api.getMailSettings flags model.query MailSettingsResp )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        SubmitResp (Ok res) ->
 | 
				
			||||||
 | 
					            if res.success then
 | 
				
			||||||
 | 
					                let
 | 
				
			||||||
 | 
					                    ( m2, c2 ) =
 | 
				
			||||||
 | 
					                        update flags (SetViewMode Table) model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    ( m3, c3 ) =
 | 
				
			||||||
 | 
					                        update flags LoadSettings m2
 | 
				
			||||||
 | 
					                in
 | 
				
			||||||
 | 
					                ( { m3 | loading = False }, Cmd.batch [ c2, c3 ] )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                ( { model | formError = Just res.message, loading = False }, Cmd.none )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        SubmitResp (Err err) ->
 | 
				
			||||||
 | 
					            ( { model | formError = Just (Util.Http.errorToString err), loading = False }, Cmd.none )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        MailSettingsResp (Ok ems) ->
 | 
				
			||||||
 | 
					            let
 | 
				
			||||||
 | 
					                m2 =
 | 
				
			||||||
 | 
					                    { model
 | 
				
			||||||
 | 
					                        | viewMode = Table
 | 
				
			||||||
 | 
					                        , loading = False
 | 
				
			||||||
 | 
					                        , tableModel = Comp.EmailSettingsTable.init ems.items
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					            in
 | 
				
			||||||
 | 
					            ( m2, Cmd.none )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        MailSettingsResp (Err _) ->
 | 
				
			||||||
 | 
					            ( { model | loading = False }, Cmd.none )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
view : Model -> Html Msg
 | 
					view : Model -> Html Msg
 | 
				
			||||||
view model =
 | 
					view model =
 | 
				
			||||||
@@ -171,10 +259,18 @@ viewForm model =
 | 
				
			|||||||
            [ Maybe.withDefault "" model.formError |> text
 | 
					            [ Maybe.withDefault "" model.formError |> text
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        , div [ class "ui divider" ] []
 | 
					        , div [ class "ui divider" ] []
 | 
				
			||||||
        , button [ class "ui primary button" ]
 | 
					        , button
 | 
				
			||||||
 | 
					            [ class "ui primary button"
 | 
				
			||||||
 | 
					            , onClick Submit
 | 
				
			||||||
 | 
					            , href "#"
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
            [ text "Submit"
 | 
					            [ text "Submit"
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        , a [ class "ui secondary button", onClick (SetViewMode Table), href "" ]
 | 
					        , a
 | 
				
			||||||
 | 
					            [ class "ui secondary button"
 | 
				
			||||||
 | 
					            , onClick (SetViewMode Table)
 | 
				
			||||||
 | 
					            , href ""
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
            [ text "Cancel"
 | 
					            [ text "Cancel"
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        , if model.formModel.settings.name /= "" then
 | 
					        , if model.formModel.settings.name /= "" then
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@ module Comp.EmailSettingsTable exposing
 | 
				
			|||||||
    ( Model
 | 
					    ( Model
 | 
				
			||||||
    , Msg
 | 
					    , Msg
 | 
				
			||||||
    , emptyModel
 | 
					    , emptyModel
 | 
				
			||||||
 | 
					    , init
 | 
				
			||||||
    , update
 | 
					    , update
 | 
				
			||||||
    , view
 | 
					    , view
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
@@ -9,10 +10,12 @@ module Comp.EmailSettingsTable exposing
 | 
				
			|||||||
import Api.Model.EmailSettings exposing (EmailSettings)
 | 
					import Api.Model.EmailSettings exposing (EmailSettings)
 | 
				
			||||||
import Html exposing (..)
 | 
					import Html exposing (..)
 | 
				
			||||||
import Html.Attributes exposing (..)
 | 
					import Html.Attributes exposing (..)
 | 
				
			||||||
 | 
					import Html.Events exposing (onClick)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type alias Model =
 | 
					type alias Model =
 | 
				
			||||||
    { emailSettings : List EmailSettings
 | 
					    { emailSettings : List EmailSettings
 | 
				
			||||||
 | 
					    , selected : Maybe EmailSettings
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,6 +27,7 @@ emptyModel =
 | 
				
			|||||||
init : List EmailSettings -> Model
 | 
					init : List EmailSettings -> Model
 | 
				
			||||||
init ems =
 | 
					init ems =
 | 
				
			||||||
    { emailSettings = ems
 | 
					    { emailSettings = ems
 | 
				
			||||||
 | 
					    , selected = Nothing
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -33,17 +37,40 @@ type Msg
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
update : Msg -> Model -> ( Model, Cmd Msg )
 | 
					update : Msg -> Model -> ( Model, Cmd Msg )
 | 
				
			||||||
update msg model =
 | 
					update msg model =
 | 
				
			||||||
    ( model, Cmd.none )
 | 
					    case msg of
 | 
				
			||||||
 | 
					        Select ems ->
 | 
				
			||||||
 | 
					            ( { model | selected = Just ems }, Cmd.none )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
view : Model -> Html Msg
 | 
					view : Model -> Html Msg
 | 
				
			||||||
view model =
 | 
					view model =
 | 
				
			||||||
    table [ class "ui table" ]
 | 
					    table [ class "ui selectable pointer table" ]
 | 
				
			||||||
        [ thead []
 | 
					        [ thead []
 | 
				
			||||||
            [ th [] [ text "Name" ]
 | 
					            [ th [ class "collapsible" ] [ text "Name" ]
 | 
				
			||||||
            , th [] [ text "Host/Port" ]
 | 
					            , th [] [ text "Host/Port" ]
 | 
				
			||||||
            , th [] [ text "From" ]
 | 
					            , th [] [ text "From" ]
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        , tbody []
 | 
					        , tbody []
 | 
				
			||||||
            []
 | 
					            (List.map (renderLine model) model.emailSettings)
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					renderLine : Model -> EmailSettings -> Html Msg
 | 
				
			||||||
 | 
					renderLine model ems =
 | 
				
			||||||
 | 
					    let
 | 
				
			||||||
 | 
					        hostport =
 | 
				
			||||||
 | 
					            case ems.smtpPort of
 | 
				
			||||||
 | 
					                Just p ->
 | 
				
			||||||
 | 
					                    ems.smtpHost ++ ":" ++ String.fromInt p
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                Nothing ->
 | 
				
			||||||
 | 
					                    ems.smtpHost
 | 
				
			||||||
 | 
					    in
 | 
				
			||||||
 | 
					    tr
 | 
				
			||||||
 | 
					        [ classList [ ( "active", model.selected == Just ems ) ]
 | 
				
			||||||
 | 
					        , onClick (Select ems)
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        [ td [ class "collapsible" ] [ text ems.name ]
 | 
				
			||||||
 | 
					        , td [] [ text hostport ]
 | 
				
			||||||
 | 
					        , td [] [ text ems.from ]
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,7 @@ type alias Model =
 | 
				
			|||||||
    , label : String
 | 
					    , label : String
 | 
				
			||||||
    , error : Maybe String
 | 
					    , error : Maybe String
 | 
				
			||||||
    , lastInput : String
 | 
					    , lastInput : String
 | 
				
			||||||
 | 
					    , optional : Bool
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -18,26 +19,27 @@ type Msg
 | 
				
			|||||||
    = SetValue String
 | 
					    = SetValue String
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
init : Maybe Int -> Maybe Int -> String -> Model
 | 
					init : Maybe Int -> Maybe Int -> Bool -> String -> Model
 | 
				
			||||||
init min max label =
 | 
					init min max opt label =
 | 
				
			||||||
    { min = min
 | 
					    { min = min
 | 
				
			||||||
    , max = max
 | 
					    , max = max
 | 
				
			||||||
    , label = label
 | 
					    , label = label
 | 
				
			||||||
    , error = Nothing
 | 
					    , error = Nothing
 | 
				
			||||||
    , lastInput = ""
 | 
					    , lastInput = ""
 | 
				
			||||||
 | 
					    , optional = opt
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tooLow : Model -> Int -> Bool
 | 
					tooLow : Model -> Int -> Bool
 | 
				
			||||||
tooLow model n =
 | 
					tooLow model n =
 | 
				
			||||||
    Maybe.map ((<) n) model.min
 | 
					    Maybe.map ((<) n) model.min
 | 
				
			||||||
        |> Maybe.withDefault False
 | 
					        |> Maybe.withDefault (not model.optional)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tooHigh : Model -> Int -> Bool
 | 
					tooHigh : Model -> Int -> Bool
 | 
				
			||||||
tooHigh model n =
 | 
					tooHigh model n =
 | 
				
			||||||
    Maybe.map ((>) n) model.max
 | 
					    Maybe.map ((>) n) model.max
 | 
				
			||||||
        |> Maybe.withDefault False
 | 
					        |> Maybe.withDefault (not model.optional)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
update : Msg -> Model -> ( Model, Maybe Int )
 | 
					update : Msg -> Model -> ( Model, Maybe Int )
 | 
				
			||||||
@@ -75,16 +77,20 @@ update msg model =
 | 
				
			|||||||
                        ( { m | error = Nothing }, Just n )
 | 
					                        ( { m | error = Nothing }, Just n )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Nothing ->
 | 
					                Nothing ->
 | 
				
			||||||
                    ( { m | error = Just ("'" ++ str ++ "' is not a valid number!") }
 | 
					                    if model.optional && String.trim str == "" then
 | 
				
			||||||
                    , Nothing
 | 
					                        ( { m | error = Nothing }, Nothing )
 | 
				
			||||||
                    )
 | 
					
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                        ( { m | error = Just ("'" ++ str ++ "' is not a valid number!") }
 | 
				
			||||||
 | 
					                        , Nothing
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
view : Maybe Int -> Model -> Html Msg
 | 
					view : Maybe Int -> String -> Model -> Html Msg
 | 
				
			||||||
view nval model =
 | 
					view nval classes model =
 | 
				
			||||||
    div
 | 
					    div
 | 
				
			||||||
        [ classList
 | 
					        [ classList
 | 
				
			||||||
            [ ( "field", True )
 | 
					            [ ( classes, True )
 | 
				
			||||||
            , ( "error", model.error /= Nothing )
 | 
					            , ( "error", model.error /= Nothing )
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,8 +13,20 @@ update flags msg model =
 | 
				
			|||||||
            let
 | 
					            let
 | 
				
			||||||
                m =
 | 
					                m =
 | 
				
			||||||
                    { model | currentTab = Just t }
 | 
					                    { model | currentTab = Just t }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                ( m2, cmd ) =
 | 
				
			||||||
 | 
					                    case t of
 | 
				
			||||||
 | 
					                        EmailSettingsTab ->
 | 
				
			||||||
 | 
					                            let
 | 
				
			||||||
 | 
					                                ( em, c ) =
 | 
				
			||||||
 | 
					                                    Comp.EmailSettingsManage.init flags
 | 
				
			||||||
 | 
					                            in
 | 
				
			||||||
 | 
					                            ( { m | emailSettingsModel = em }, Cmd.map EmailSettingsMsg c )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        ChangePassTab ->
 | 
				
			||||||
 | 
					                            ( m, Cmd.none )
 | 
				
			||||||
            in
 | 
					            in
 | 
				
			||||||
            ( m, Cmd.none )
 | 
					            ( m2, cmd )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ChangePassMsg m ->
 | 
					        ChangePassMsg m ->
 | 
				
			||||||
            let
 | 
					            let
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -88,6 +88,10 @@
 | 
				
			|||||||
    background-color: #d8dfe5;
 | 
					    background-color: #d8dfe5;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ui.selectable.pointer.table tr {
 | 
				
			||||||
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
span.small-info {
 | 
					span.small-info {
 | 
				
			||||||
    font-size: smaller;
 | 
					    font-size: smaller;
 | 
				
			||||||
    color: rgba(0,0,0,0.6);
 | 
					    color: rgba(0,0,0,0.6);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user