diff --git a/modules/backend/src/main/scala/docspell/backend/signup/ExternalAccount.scala b/modules/backend/src/main/scala/docspell/backend/signup/ExternalAccount.scala new file mode 100644 index 00000000..2923a57f --- /dev/null +++ b/modules/backend/src/main/scala/docspell/backend/signup/ExternalAccount.scala @@ -0,0 +1,13 @@ +package docspell.backend.signup + +import docspell.common._ + +final case class ExternalAccount( + collName: Ident, + login: Ident, + source: AccountSource +) { + + def toAccountId: AccountId = + AccountId(collName, login) +} diff --git a/modules/backend/src/main/scala/docspell/backend/signup/OSignup.scala b/modules/backend/src/main/scala/docspell/backend/signup/OSignup.scala index 89a10866..15a9de16 100644 --- a/modules/backend/src/main/scala/docspell/backend/signup/OSignup.scala +++ b/modules/backend/src/main/scala/docspell/backend/signup/OSignup.scala @@ -8,13 +8,11 @@ package docspell.backend.signup import cats.effect.{Async, Resource} import cats.implicits._ - import docspell.backend.PasswordCrypt import docspell.common._ import docspell.common.syntax.all._ import docspell.store.records.{RCollective, RInvitation, RUser} import docspell.store.{AddResult, Store} - import doobie.free.connection.ConnectionIO import org.log4s.getLogger @@ -22,6 +20,9 @@ trait OSignup[F[_]] { def register(cfg: Config)(data: RegisterData): F[SignupResult] + /** Creates the given account if it doesn't exist. */ + def setupExternal(cfg: Config)(data: ExternalAccount): F[SignupResult] + def newInvite(cfg: Config)(password: Password): F[NewInviteResult] } @@ -76,6 +77,31 @@ object OSignup { } } + def setupExternal(cfg: Config)(data: ExternalAccount): F[SignupResult] = + cfg.mode match { + case Config.Mode.Closed => + SignupResult.signupClosed.pure[F] + case _ => + if (data.source == AccountSource.Local) + SignupResult.failure(new Exception("Account source must not be LOCAL!")).pure[F] + else for { + recs <- makeRecords(data.collName, data.login, Password(""), data.source) + cres <- store.add(RCollective.insert(recs._1), RCollective.existsById(data.collName)) + ures <- store.add(RUser.insert(recs._2), RUser.exists(data.login)) + res = cres match { + case AddResult.Failure(ex) => + SignupResult.failure(ex) + case _ => + ures match { + case AddResult.Failure(ex) => + SignupResult.failure(ex) + case _ => + SignupResult.success + } + } + } yield res + } + private def retryInvite(res: SignupResult): Boolean = res match { case SignupResult.CollectiveExists => @@ -91,31 +117,6 @@ object OSignup { } private def addUser(data: RegisterData): F[AddResult] = { - def toRecords: F[(RCollective, RUser)] = - for { - id2 <- Ident.randomId[F] - now <- Timestamp.current[F] - c = RCollective( - data.collName, - CollectiveState.Active, - Language.German, - true, - now - ) - u = RUser( - id2, - data.login, - data.collName, - PasswordCrypt.crypt(data.password), - UserState.Active, - AccountSource.Local, - None, - 0, - None, - now - ) - } yield (c, u) - def insert(coll: RCollective, user: RUser): ConnectionIO[Int] = for { n1 <- RCollective.insert(coll) @@ -127,9 +128,29 @@ object OSignup { val msg = s"The collective '${data.collName}' already exists." for { - cu <- toRecords + cu <- makeRecords(data.collName, data.login, data.password, AccountSource.Local) save <- store.add(insert(cu._1, cu._2), collectiveExists) } yield save.fold(identity, _.withMsg(msg), identity) } + + private def makeRecords( + collName: Ident, + login: Ident, + password: Password, + source: AccountSource + ): F[(RCollective, RUser)] = + for { + id2 <- Ident.randomId[F] + now <- Timestamp.current[F] + c = RCollective.makeDefault(collName, now) + u = RUser.makeDefault( + id2, + login, + collName, + PasswordCrypt.crypt(password), + source, + now + ) + } yield (c, u) }) } diff --git a/modules/store/src/main/scala/docspell/store/records/RCollective.scala b/modules/store/src/main/scala/docspell/store/records/RCollective.scala index 43b7e382..5d3fc97c 100644 --- a/modules/store/src/main/scala/docspell/store/records/RCollective.scala +++ b/modules/store/src/main/scala/docspell/store/records/RCollective.scala @@ -37,6 +37,9 @@ object RCollective { val all = NonEmptyList.of[Column[_]](id, state, language, integration, created) } + def makeDefault(collName: Ident, created: Timestamp): RCollective = + RCollective(collName, CollectiveState.Active, Language.German, true, created) + val T = Table(None) def as(alias: String): Table = Table(Some(alias)) diff --git a/modules/store/src/main/scala/docspell/store/records/RUser.scala b/modules/store/src/main/scala/docspell/store/records/RUser.scala index 586d29b4..57b23ad8 100644 --- a/modules/store/src/main/scala/docspell/store/records/RUser.scala +++ b/modules/store/src/main/scala/docspell/store/records/RUser.scala @@ -29,6 +29,28 @@ case class RUser( ) {} object RUser { + + def makeDefault( + id: Ident, + login: Ident, + collName: Ident, + password: Password, + source: AccountSource, + created: Timestamp + ): RUser = + RUser( + id, + login, + collName, + password, + UserState.Active, + source, + None, + 0, + None, + created + ) + final case class Table(alias: Option[String]) extends TableDef { val tableName = "user_"