mirror of
				https://github.com/TheAnachronism/docspell.git
				synced 2025-10-31 17:50:11 +00:00 
			
		
		
		
	Converting user and userimap records
This commit is contained in:
		| @@ -144,6 +144,7 @@ object RegexNerFile { | ||||
|       def max(col: Column, table: Fragment, cidCol: Column): Fragment = | ||||
|         selectSimple(col.max ++ fr"as t", table, cidCol.is(collective)) | ||||
|  | ||||
|       val equip = REquipment.as("e") | ||||
|       val sql = | ||||
|         List( | ||||
|           max( | ||||
| @@ -152,7 +153,11 @@ object RegexNerFile { | ||||
|             ROrganization.Columns.cid | ||||
|           ), | ||||
|           max(RPerson.Columns.updated, RPerson.table, RPerson.Columns.cid), | ||||
|           max(REquipment.Columns.updated, REquipment.table, REquipment.Columns.cid) | ||||
|           max( | ||||
|             equip.updated.oldColumn, | ||||
|             Fragment.const(equip.tableName), | ||||
|             equip.cid.oldColumn | ||||
|           ) | ||||
|         ) | ||||
|           .reduce(_ ++ fr"UNION ALL" ++ _) | ||||
|  | ||||
|   | ||||
| @@ -5,5 +5,16 @@ object Implicits extends DoobieMeta with DoobieSyntax { | ||||
|   implicit final class LegacySyntax(col: docspell.store.qb.Column[_]) { | ||||
|     def oldColumn: Column = | ||||
|       Column(col.name) | ||||
|  | ||||
|     def column: Column = { | ||||
|       val c = col.alias match { | ||||
|         case Some(a) => oldColumn.as(a) | ||||
|         case None    => oldColumn | ||||
|       } | ||||
|       col.table.alias match { | ||||
|         case Some(p) => c.prefix(p) | ||||
|         case None    => c | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,8 @@ | ||||
| package docspell.store.qb | ||||
|  | ||||
| case class Column[A](name: String, table: TableDef, alias: Option[String] = None) | ||||
| case class Column[A](name: String, table: TableDef, alias: Option[String] = None) { | ||||
|   def as(alias: String): Column[A] = | ||||
|     copy(alias = Some(alias)) | ||||
| } | ||||
|  | ||||
| object Column {} | ||||
|   | ||||
| @@ -13,6 +13,8 @@ object Condition { | ||||
|   case class CompareCol[A](col1: Column[A], op: Operator, col2: Column[A]) | ||||
|       extends Condition | ||||
|  | ||||
|   case class InSubSelect[A](col: Column[A], subSelect: Select) extends Condition | ||||
|  | ||||
|   case class And(c: Condition, cs: Vector[Condition]) extends Condition | ||||
|   case class Or(c: Condition, cs: Vector[Condition])  extends Condition | ||||
|   case class Not(c: Condition)                        extends Condition | ||||
|   | ||||
| @@ -72,9 +72,17 @@ trait DSL extends DoobieMeta { | ||||
|     def ===(value: A)(implicit P: Put[A]): Condition = | ||||
|       Condition.CompareVal(col, Operator.Eq, value) | ||||
|  | ||||
|     //TODO find some better way around the cast | ||||
|     def ====(value: String): Condition = | ||||
|       Condition.CompareVal(col.asInstanceOf[Column[String]], Operator.Eq, value) | ||||
|  | ||||
|     def like(value: A)(implicit P: Put[A]): Condition = | ||||
|       Condition.CompareVal(col, Operator.LowerLike, value) | ||||
|  | ||||
|     //TODO find some better way around the cast | ||||
|     def likes(value: String): Condition = | ||||
|       Condition.CompareVal(col.asInstanceOf[Column[String]], Operator.LowerLike, value) | ||||
|  | ||||
|     def <=(value: A)(implicit P: Put[A]): Condition = | ||||
|       Condition.CompareVal(col, Operator.Lte, value) | ||||
|  | ||||
| @@ -87,6 +95,9 @@ trait DSL extends DoobieMeta { | ||||
|     def <(value: A)(implicit P: Put[A]): Condition = | ||||
|       Condition.CompareVal(col, Operator.Lt, value) | ||||
|  | ||||
|     def in(subsel: Select): Condition = | ||||
|       Condition.InSubSelect(col, subsel) | ||||
|  | ||||
|     def ===(other: Column[A]): Condition = | ||||
|       Condition.CompareCol(col, Operator.Eq, other) | ||||
|   } | ||||
|   | ||||
| @@ -33,6 +33,10 @@ object ConditionBuilder { | ||||
|         } | ||||
|         c1Frag ++ operator(op) ++ c2Frag | ||||
|  | ||||
|       case Condition.InSubSelect(col, subsel) => | ||||
|         val sub = DoobieQuery(subsel) | ||||
|         SelectExprBuilder.column(col) ++ sql" IN (" ++ sub ++ sql")" | ||||
|  | ||||
|       case Condition.And(c, cs) => | ||||
|         val inner = cs.prepended(c).map(build).reduce(_ ++ and ++ _) | ||||
|         if (cs.isEmpty) inner | ||||
|   | ||||
| @@ -136,15 +136,16 @@ object QFolder { | ||||
|   } | ||||
|  | ||||
|   def findById(id: Ident, account: AccountId): ConnectionIO[Option[FolderDetail]] = { | ||||
|     val user      = RUser.as("u") | ||||
|     val mUserId   = RFolderMember.Columns.user.prefix("m") | ||||
|     val mFolderId = RFolderMember.Columns.folder.prefix("m") | ||||
|     val uId       = RUser.Columns.uid.prefix("u") | ||||
|     val uLogin    = RUser.Columns.login.prefix("u") | ||||
|     val uId       = user.uid.column | ||||
|     val uLogin    = user.login.column | ||||
|     val sColl     = RFolder.Columns.collective.prefix("s") | ||||
|     val sId       = RFolder.Columns.id.prefix("s") | ||||
|  | ||||
|     val from = RFolderMember.table ++ fr"m INNER JOIN" ++ | ||||
|       RUser.table ++ fr"u ON" ++ mUserId.is(uId) ++ fr"INNER JOIN" ++ | ||||
|       Fragment.const(user.tableName) ++ fr"u ON" ++ mUserId.is(uId) ++ fr"INNER JOIN" ++ | ||||
|       RFolder.table ++ fr"s ON" ++ mFolderId.is(sId) | ||||
|  | ||||
|     val memberQ = selectSimple( | ||||
| @@ -187,8 +188,9 @@ object QFolder { | ||||
| // inner join user_ u on u.uid = s.owner | ||||
| // where s.cid = 'eike'; | ||||
|  | ||||
|     val uId     = RUser.Columns.uid.prefix("u") | ||||
|     val uLogin  = RUser.Columns.login.prefix("u") | ||||
|     val user    = RUser.as("u") | ||||
|     val uId     = user.uid.column | ||||
|     val uLogin  = user.login.column | ||||
|     val sId     = RFolder.Columns.id.prefix("s") | ||||
|     val sOwner  = RFolder.Columns.owner.prefix("s") | ||||
|     val sName   = RFolder.Columns.name.prefix("s") | ||||
| @@ -199,11 +201,11 @@ object QFolder { | ||||
|     //CTE | ||||
|     val cte: Fragment = { | ||||
|       val from1 = RFolderMember.table ++ fr"m INNER JOIN" ++ | ||||
|         RUser.table ++ fr"u ON" ++ uId.is(mUser) ++ fr"INNER JOIN" ++ | ||||
|         Fragment.const(user.tableName) ++ fr"u ON" ++ uId.is(mUser) ++ fr"INNER JOIN" ++ | ||||
|         RFolder.table ++ fr"s ON" ++ sId.is(mFolder) | ||||
|  | ||||
|       val from2 = RFolder.table ++ fr"s INNER JOIN" ++ | ||||
|         RUser.table ++ fr"u ON" ++ uId.is(sOwner) | ||||
|         Fragment.const(user.tableName) ++ fr"u ON" ++ uId.is(sOwner) | ||||
|  | ||||
|       withCTE( | ||||
|         "memberlogin" -> | ||||
| @@ -232,7 +234,7 @@ object QFolder { | ||||
|     ) | ||||
|  | ||||
|     val from = RFolder.table ++ fr"s INNER JOIN" ++ | ||||
|       RUser.table ++ fr"u ON" ++ uId.is(sOwner) | ||||
|       Fragment.const(user.tableName) ++ fr"u ON" ++ uId.is(sOwner) | ||||
|  | ||||
|     val where = | ||||
|       sColl.is(account.collective) :: idQ.toList | ||||
| @@ -247,17 +249,20 @@ object QFolder { | ||||
|  | ||||
|   /** Select all folder_id where the given account is member or owner. */ | ||||
|   def findMemberFolderIds(account: AccountId): Fragment = { | ||||
|     val user    = RUser.as("u") | ||||
|     val fId     = RFolder.Columns.id.prefix("f") | ||||
|     val fOwner  = RFolder.Columns.owner.prefix("f") | ||||
|     val fColl   = RFolder.Columns.collective.prefix("f") | ||||
|     val uId     = RUser.Columns.uid.prefix("u") | ||||
|     val uLogin  = RUser.Columns.login.prefix("u") | ||||
|     val uId     = user.uid.column | ||||
|     val uLogin  = user.login.column | ||||
|     val mFolder = RFolderMember.Columns.folder.prefix("m") | ||||
|     val mUser   = RFolderMember.Columns.user.prefix("m") | ||||
|  | ||||
|     selectSimple( | ||||
|       Seq(fId), | ||||
|       RFolder.table ++ fr"f INNER JOIN" ++ RUser.table ++ fr"u ON" ++ fOwner.is(uId), | ||||
|       RFolder.table ++ fr"f INNER JOIN" ++ Fragment.const( | ||||
|         user.tableName | ||||
|       ) ++ fr"u ON" ++ fOwner.is(uId), | ||||
|       and(fColl.is(account.collective), uLogin.is(account.user)) | ||||
|     ) ++ | ||||
|       fr"UNION ALL" ++ | ||||
| @@ -266,7 +271,7 @@ object QFolder { | ||||
|         RFolderMember.table ++ fr"m INNER JOIN" ++ RFolder.table ++ fr"f ON" ++ fId.is( | ||||
|           mFolder | ||||
|         ) ++ | ||||
|           fr"INNER JOIN" ++ RUser.table ++ fr"u ON" ++ uId.is(mUser), | ||||
|           fr"INNER JOIN" ++ Fragment.const(user.tableName) ++ fr"u ON" ++ uId.is(mUser), | ||||
|         and(fColl.is(account.collective), uLogin.is(account.user)) | ||||
|       ) | ||||
|   } | ||||
|   | ||||
| @@ -5,7 +5,6 @@ import cats.data.OptionT | ||||
| import docspell.common._ | ||||
| import docspell.store.impl.Implicits._ | ||||
| import docspell.store.records.RCollective.{Columns => CC} | ||||
| import docspell.store.records.RUser.{Columns => UC} | ||||
| import docspell.store.records.{RCollective, RRememberMe, RUser} | ||||
|  | ||||
| import doobie._ | ||||
| @@ -23,16 +22,17 @@ object QLogin { | ||||
|   ) | ||||
|  | ||||
|   def findUser(acc: AccountId): ConnectionIO[Option[Data]] = { | ||||
|     val ucid   = UC.cid.prefix("u") | ||||
|     val login  = UC.login.prefix("u") | ||||
|     val pass   = UC.password.prefix("u") | ||||
|     val ustate = UC.state.prefix("u") | ||||
|     val user   = RUser.as("u") | ||||
|     val ucid   = user.cid.column | ||||
|     val login  = user.login.column | ||||
|     val pass   = user.password.column | ||||
|     val ustate = user.state.column | ||||
|     val cstate = CC.state.prefix("c") | ||||
|     val ccid   = CC.id.prefix("c") | ||||
|  | ||||
|     val sql = selectSimple( | ||||
|       List(ucid, login, pass, cstate, ustate), | ||||
|       RUser.table ++ fr"u, " ++ RCollective.table ++ fr"c", | ||||
|       Fragment.const(user.tableName) ++ fr"u, " ++ RCollective.table ++ fr"c", | ||||
|       and(ucid.is(ccid), login.is(acc.user), ucid.is(acc.collective)) | ||||
|     ) | ||||
|  | ||||
|   | ||||
| @@ -45,19 +45,20 @@ object QMails { | ||||
|   } | ||||
|  | ||||
|   private def partialFind: (Seq[Column], Fragment) = { | ||||
|     val iId    = RItem.Columns.id.prefix("i") | ||||
|     val tItem  = RSentMailItem.Columns.itemId.prefix("t") | ||||
|     val tMail  = RSentMailItem.Columns.sentMailId.prefix("t") | ||||
|     val mId    = RSentMail.Columns.id.prefix("m") | ||||
|     val mUser  = RSentMail.Columns.uid.prefix("m") | ||||
|     val uId    = RUser.Columns.uid.prefix("u") | ||||
|     val uLogin = RUser.Columns.login.prefix("u") | ||||
|     val user  = RUser.as("u") | ||||
|     val iId   = RItem.Columns.id.prefix("i") | ||||
|     val tItem = RSentMailItem.Columns.itemId.prefix("t") | ||||
|     val tMail = RSentMailItem.Columns.sentMailId.prefix("t") | ||||
|     val mId   = RSentMail.Columns.id.prefix("m") | ||||
|     val mUser = RSentMail.Columns.uid.prefix("m") | ||||
|  | ||||
|     val cols = RSentMail.Columns.all.map(_.prefix("m")) :+ uLogin | ||||
|     val cols = RSentMail.Columns.all.map(_.prefix("m")) :+ user.login.column | ||||
|     val from = RSentMail.table ++ fr"m INNER JOIN" ++ | ||||
|       RSentMailItem.table ++ fr"t ON" ++ tMail.is(mId) ++ | ||||
|       fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ tItem.is(iId) ++ | ||||
|       fr"INNER JOIN" ++ RUser.table ++ fr"u ON" ++ uId.is(mUser) | ||||
|       fr"INNER JOIN" ++ Fragment.const(user.tableName) ++ fr"u ON" ++ user.uid.column.is( | ||||
|         mUser | ||||
|       ) | ||||
|  | ||||
|     (cols, from) | ||||
|   } | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| package docspell.store.records | ||||
|  | ||||
| import docspell.common._ | ||||
| import docspell.store.impl.Implicits._ | ||||
| import docspell.store.impl._ | ||||
| import docspell.store.qb.DSL._ | ||||
| import docspell.store.qb._ | ||||
|  | ||||
| import doobie._ | ||||
| import doobie.implicits._ | ||||
| @@ -20,86 +20,99 @@ case class RUser( | ||||
| ) {} | ||||
|  | ||||
| object RUser { | ||||
|   final case class Table(alias: Option[String]) extends TableDef { | ||||
|     val tableName = "user_" | ||||
|  | ||||
|   val table = fr"user_" | ||||
|  | ||||
|   object Columns { | ||||
|     val uid        = Column("uid") | ||||
|     val cid        = Column("cid") | ||||
|     val login      = Column("login") | ||||
|     val password   = Column("password") | ||||
|     val state      = Column("state") | ||||
|     val email      = Column("email") | ||||
|     val loginCount = Column("logincount") | ||||
|     val lastLogin  = Column("lastlogin") | ||||
|     val created    = Column("created") | ||||
|     val uid        = Column[Ident]("uid", this) | ||||
|     val login      = Column[Ident]("login", this) | ||||
|     val cid        = Column[Ident]("cid", this) | ||||
|     val password   = Column[Password]("password", this) | ||||
|     val state      = Column[UserState]("state", this) | ||||
|     val email      = Column[String]("email", this) | ||||
|     val loginCount = Column[Int]("logincount", this) | ||||
|     val lastLogin  = Column[Timestamp]("lastlogin", this) | ||||
|     val created    = Column[Timestamp]("created", this) | ||||
|  | ||||
|     val all = | ||||
|       List(uid, login, cid, password, state, email, loginCount, lastLogin, created) | ||||
|   } | ||||
|  | ||||
|   import Columns._ | ||||
|   def as(alias: String): Table = | ||||
|     Table(Some(alias)) | ||||
|  | ||||
|   def insert(v: RUser): ConnectionIO[Int] = { | ||||
|     val sql = insertRow( | ||||
|       table, | ||||
|       Columns.all, | ||||
|     val t = Table(None) | ||||
|     val sql = DML.insert( | ||||
|       t, | ||||
|       t.all, | ||||
|       fr"${v.uid},${v.login},${v.cid},${v.password},${v.state},${v.email},${v.loginCount},${v.lastLogin},${v.created}" | ||||
|     ) | ||||
|     sql.update.run | ||||
|   } | ||||
|  | ||||
|   def update(v: RUser): ConnectionIO[Int] = { | ||||
|     val sql = updateRow( | ||||
|       table, | ||||
|       and(login.is(v.login), cid.is(v.cid)), | ||||
|       commas( | ||||
|         state.setTo(v.state), | ||||
|         email.setTo(v.email), | ||||
|         loginCount.setTo(v.loginCount), | ||||
|         lastLogin.setTo(v.lastLogin) | ||||
|     val t = Table(None) | ||||
|     DML.update( | ||||
|       t, | ||||
|       t.login === v.login && t.cid === v.cid, | ||||
|       DML.set( | ||||
|         t.state.setTo(v.state), | ||||
|         t.email.setTo(v.email), | ||||
|         t.loginCount.setTo(v.loginCount), | ||||
|         t.lastLogin.setTo(v.lastLogin) | ||||
|       ) | ||||
|     ) | ||||
|     sql.update.run | ||||
|   } | ||||
|  | ||||
|   def exists(loginName: Ident): ConnectionIO[Boolean] = | ||||
|     selectCount(uid, table, login.is(loginName)).query[Int].unique.map(_ > 0) | ||||
|   def exists(loginName: Ident): ConnectionIO[Boolean] = { | ||||
|     val t = Table(None) | ||||
|     run(select(count(t.uid)), from(t), t.login === loginName).query[Int].unique.map(_ > 0) | ||||
|   } | ||||
|  | ||||
|   def findByAccount(aid: AccountId): ConnectionIO[Option[RUser]] = { | ||||
|     val sql = selectSimple(all, table, and(cid.is(aid.collective), login.is(aid.user))) | ||||
|     val t = Table(None) | ||||
|     val sql = | ||||
|       run(select(t.all), from(t), t.cid === aid.collective && t.login === aid.user) | ||||
|     sql.query[RUser].option | ||||
|   } | ||||
|  | ||||
|   def findById(userId: Ident): ConnectionIO[Option[RUser]] = { | ||||
|     val sql = selectSimple(all, table, uid.is(userId)) | ||||
|     val t   = Table(None) | ||||
|     val sql = run(select(t.all), from(t), t.uid === userId) | ||||
|     sql.query[RUser].option | ||||
|   } | ||||
|  | ||||
|   def findAll(coll: Ident, order: Columns.type => Column): ConnectionIO[Vector[RUser]] = { | ||||
|     val sql = selectSimple(all, table, cid.is(coll)) ++ orderBy(order(Columns).f) | ||||
|   def findAll(coll: Ident, order: Table => Column[_]): ConnectionIO[Vector[RUser]] = { | ||||
|     val t   = Table(None) | ||||
|     val sql = Select(select(t.all), from(t), t.cid === coll).orderBy(order(t)).run | ||||
|     sql.query[RUser].to[Vector] | ||||
|   } | ||||
|  | ||||
|   def updateLogin(accountId: AccountId): ConnectionIO[Int] = | ||||
|     currentTime.flatMap(t => | ||||
|       updateRow( | ||||
|         table, | ||||
|         and(cid.is(accountId.collective), login.is(accountId.user)), | ||||
|         commas( | ||||
|           loginCount.f ++ fr"=" ++ loginCount.f ++ fr"+ 1", | ||||
|           lastLogin.setTo(t) | ||||
|   def updateLogin(accountId: AccountId): ConnectionIO[Int] = { | ||||
|     val t = Table(None) | ||||
|     def stmt(now: Timestamp) = | ||||
|       DML.update( | ||||
|         t, | ||||
|         t.cid === accountId.collective && t.login === accountId.user, | ||||
|         DML.set( | ||||
|           t.loginCount.increment(1), | ||||
|           t.lastLogin.setTo(now) | ||||
|         ) | ||||
|       ).update.run | ||||
|       ) | ||||
|     Timestamp.current[ConnectionIO].flatMap(stmt) | ||||
|   } | ||||
|  | ||||
|   def updatePassword(accountId: AccountId, hashedPass: Password): ConnectionIO[Int] = { | ||||
|     val t = Table(None) | ||||
|     DML.update( | ||||
|       t, | ||||
|       t.cid === accountId.collective && t.login === accountId.user, | ||||
|       DML.set(t.password.setTo(hashedPass)) | ||||
|     ) | ||||
|   } | ||||
|  | ||||
|   def updatePassword(accountId: AccountId, hashedPass: Password): ConnectionIO[Int] = | ||||
|     updateRow( | ||||
|       table, | ||||
|       and(cid.is(accountId.collective), login.is(accountId.user)), | ||||
|       password.setTo(hashedPass) | ||||
|     ).update.run | ||||
|  | ||||
|   def delete(user: Ident, coll: Ident): ConnectionIO[Int] = | ||||
|     deleteFrom(table, and(cid.is(coll), login.is(user))).update.run | ||||
|   def delete(user: Ident, coll: Ident): ConnectionIO[Int] = { | ||||
|     val t = Table(None) | ||||
|     DML.delete(t, t.cid === coll && t.login === user).update.run | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -168,12 +168,16 @@ object RUserEmail { | ||||
|       nameQ: Option[String], | ||||
|       exact: Boolean | ||||
|   ): Query0[RUserEmail] = { | ||||
|     val user   = RUser.as("u") | ||||
|     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 uId    = user.uid.column | ||||
|     val uColl  = user.cid.column | ||||
|     val uLogin = user.login.column | ||||
|     val from = | ||||
|       table ++ fr"m INNER JOIN" ++ Fragment.const(user.tableName) ++ 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)          => Seq(mName.lowerLike(s"%${str.toLowerCase}%")) | ||||
| @@ -194,14 +198,19 @@ object RUserEmail { | ||||
|     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 user   = RUser.as("u") | ||||
|     val uId    = user.uid.column | ||||
|     val uColl  = user.cid.column | ||||
|     val uLogin = user.login.column | ||||
|     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 | ||||
|       fr"uid in (" ++ selectSimple( | ||||
|         Seq(uId), | ||||
|         Fragment.const(user.tableName), | ||||
|         and(cond) | ||||
|       ) ++ fr") AND" ++ name | ||||
|         .is( | ||||
|           connName | ||||
|         ) | ||||
|   | ||||
| @@ -5,8 +5,8 @@ import cats.effect._ | ||||
| import cats.implicits._ | ||||
|  | ||||
| import docspell.common._ | ||||
| import docspell.store.impl.Column | ||||
| import docspell.store.impl.Implicits._ | ||||
| import docspell.store.qb.DSL._ | ||||
| import docspell.store.qb._ | ||||
|  | ||||
| import doobie._ | ||||
| import doobie.implicits._ | ||||
| @@ -92,19 +92,19 @@ object RUserImap { | ||||
|       now | ||||
|     ) | ||||
|  | ||||
|   val table = fr"userimap" | ||||
|   final case class Table(alias: Option[String]) extends TableDef { | ||||
|     val tableName = "userimap" | ||||
|  | ||||
|   object Columns { | ||||
|     val id            = Column("id") | ||||
|     val uid           = Column("uid") | ||||
|     val name          = Column("name") | ||||
|     val imapHost      = Column("imap_host") | ||||
|     val imapPort      = Column("imap_port") | ||||
|     val imapUser      = Column("imap_user") | ||||
|     val imapPass      = Column("imap_password") | ||||
|     val imapSsl       = Column("imap_ssl") | ||||
|     val imapCertCheck = Column("imap_certcheck") | ||||
|     val created       = Column("created") | ||||
|     val id            = Column[Ident]("id", this) | ||||
|     val uid           = Column[Ident]("uid", this) | ||||
|     val name          = Column[Ident]("name", this) | ||||
|     val imapHost      = Column[String]("imap_host", this) | ||||
|     val imapPort      = Column[Int]("imap_port", this) | ||||
|     val imapUser      = Column[String]("imap_user", this) | ||||
|     val imapPass      = Column[Password]("imap_password", this) | ||||
|     val imapSsl       = Column[SSLType]("imap_ssl", this) | ||||
|     val imapCertCheck = Column[Boolean]("imap_certcheck", this) | ||||
|     val created       = Column[Timestamp]("created", this) | ||||
|  | ||||
|     val all = List( | ||||
|       id, | ||||
| @@ -120,52 +120,64 @@ object RUserImap { | ||||
|     ) | ||||
|   } | ||||
|  | ||||
|   import Columns._ | ||||
|   def as(alias: String): Table = | ||||
|     Table(Some(alias)) | ||||
|  | ||||
|   def insert(v: RUserImap): ConnectionIO[Int] = | ||||
|     insertRow( | ||||
|       table, | ||||
|       all, | ||||
|       sql"${v.id},${v.uid},${v.name},${v.imapHost},${v.imapPort},${v.imapUser},${v.imapPassword},${v.imapSsl},${v.imapCertCheck},${v.created}" | ||||
|     ).update.run | ||||
|  | ||||
|   def update(eId: Ident, v: RUserImap): ConnectionIO[Int] = | ||||
|     updateRow( | ||||
|       table, | ||||
|       id.is(eId), | ||||
|       commas( | ||||
|         name.setTo(v.name), | ||||
|         imapHost.setTo(v.imapHost), | ||||
|         imapPort.setTo(v.imapPort), | ||||
|         imapUser.setTo(v.imapUser), | ||||
|         imapPass.setTo(v.imapPassword), | ||||
|         imapSsl.setTo(v.imapSsl), | ||||
|         imapCertCheck.setTo(v.imapCertCheck) | ||||
|   def insert(v: RUserImap): ConnectionIO[Int] = { | ||||
|     val t = Table(None) | ||||
|     DML | ||||
|       .insert( | ||||
|         t, | ||||
|         t.all, | ||||
|         sql"${v.id},${v.uid},${v.name},${v.imapHost},${v.imapPort},${v.imapUser},${v.imapPassword},${v.imapSsl},${v.imapCertCheck},${v.created}" | ||||
|       ) | ||||
|     ).update.run | ||||
|       .update | ||||
|       .run | ||||
|   } | ||||
|  | ||||
|   def findByUser(userId: Ident): ConnectionIO[Vector[RUserImap]] = | ||||
|     selectSimple(all, table, uid.is(userId)).query[RUserImap].to[Vector] | ||||
|   def update(eId: Ident, v: RUserImap): ConnectionIO[Int] = { | ||||
|     val t = Table(None) | ||||
|     DML.update( | ||||
|       t, | ||||
|       t.id === eId, | ||||
|       DML.set( | ||||
|         t.name.setTo(v.name), | ||||
|         t.imapHost.setTo(v.imapHost), | ||||
|         t.imapPort.setTo(v.imapPort), | ||||
|         t.imapUser.setTo(v.imapUser), | ||||
|         t.imapPass.setTo(v.imapPassword), | ||||
|         t.imapSsl.setTo(v.imapSsl), | ||||
|         t.imapCertCheck.setTo(v.imapCertCheck) | ||||
|       ) | ||||
|     ) | ||||
|   } | ||||
|  | ||||
|   def findByUser(userId: Ident): ConnectionIO[Vector[RUserImap]] = { | ||||
|     val t = Table(None) | ||||
|     run(select(t.all), from(t), t.uid === userId).query[RUserImap].to[Vector] | ||||
|   } | ||||
|  | ||||
|   private def findByAccount0( | ||||
|       accId: AccountId, | ||||
|       nameQ: Option[String], | ||||
|       exact: Boolean | ||||
|   ): Query0[RUserImap] = { | ||||
|     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)          => Seq(mName.lowerLike(s"%${str.toLowerCase}%")) | ||||
|       case None               => Seq.empty | ||||
|     }) | ||||
|     val m = RUserImap.as("m") | ||||
|     val u = RUser.as("u") | ||||
|  | ||||
|     (selectSimple(all.map(_.prefix("m")), from, and(cond)) ++ orderBy(mName.f)) | ||||
|       .query[RUserImap] | ||||
|     val nameFilter = | ||||
|       nameQ.map { str => | ||||
|         if (exact) m.name ==== str | ||||
|         else m.name.likes(s"%${str.toLowerCase}%") | ||||
|       } | ||||
|  | ||||
|     val sql = Select( | ||||
|       select(m.all), | ||||
|       from(m).innerJoin(u, m.uid === u.uid), | ||||
|       u.cid === accId.collective && u.login === accId.user &&? nameFilter | ||||
|     ).orderBy(m.name).run | ||||
|  | ||||
|     sql.query[RUserImap] | ||||
|   } | ||||
|  | ||||
|   def findByAccount( | ||||
| @@ -178,26 +190,28 @@ object RUserImap { | ||||
|     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)) | ||||
|     val t = Table(None) | ||||
|     val u = RUser.as("u") | ||||
|     val subsel = | ||||
|       Select(select(u.uid), from(u), u.cid === accId.collective && u.login === accId.user) | ||||
|  | ||||
|     deleteFrom( | ||||
|       table, | ||||
|       fr"uid in (" ++ selectSimple(Seq(uId), RUser.table, and(cond)) ++ fr") AND" ++ name | ||||
|         .is( | ||||
|           connName | ||||
|         ) | ||||
|     ).update.run | ||||
|     DML | ||||
|       .delete( | ||||
|         t, | ||||
|         t.uid.in(subsel) && t.name === connName | ||||
|       ) | ||||
|       .update | ||||
|       .run | ||||
|   } | ||||
|  | ||||
|   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))) | ||||
|   def exists(userId: Ident, connName: Ident): ConnectionIO[Boolean] = { | ||||
|     val t = Table(None) | ||||
|     run(select(count(t.id)), from(t), t.uid === userId && t.name === connName) | ||||
|       .query[Int] | ||||
|       .unique | ||||
|       .map(_ > 0) | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user