~jan0sch/smederee

Showing details for patch b580cc42faa2d739e1aecf525c6af72b26e78a2b.
2023-02-04 (Sat), 8:08 AM - Jens Grassel - b580cc42faa2d739e1aecf525c6af72b26e78a2b

VCS: Refactor repository access into separate function.

Summary of changes
1 files modified with 58 lines added and 86 lines removed
  • modules/hub/src/main/scala/de/smederee/hub/VcsRepositoryRoutes.scala with 58 added and 86 removed lines
diff -rN -u old-smederee/modules/hub/src/main/scala/de/smederee/hub/VcsRepositoryRoutes.scala new-smederee/modules/hub/src/main/scala/de/smederee/hub/VcsRepositoryRoutes.scala
--- old-smederee/modules/hub/src/main/scala/de/smederee/hub/VcsRepositoryRoutes.scala	2025-01-31 22:36:58.684300233 +0000
+++ new-smederee/modules/hub/src/main/scala/de/smederee/hub/VcsRepositoryRoutes.scala	2025-01-31 22:36:58.684300233 +0000
@@ -71,6 +71,43 @@
   // The base URI for our site which that be passed into some templates which create links themselfes.
   private val baseUri = linkConfig.createFullUri(Uri())
 
+  /** Load the repository metadata with the given owner and name from the database and return it and its primary key id
+    * if the repository exists and is readable by the given user account.
+    *
+    * @param currentUser
+    *   The user account that is requesting access to the repository or None for a guest user.
+    * @param repositoryOwnerName
+    *   The name of the account that owns the repository.
+    * @param repositoryName
+    *   The name of the repository. A repository name must start with a letter or number and must contain only
+    *   alphanumeric ASCII characters as well as minus or underscore signs. It must be between 2 and 64 characters long.
+    * @return
+    *   An option to a tuple holding the [[VcsRepository]] and its primary key id.
+    */
+  private def loadRepo(
+      currentUser: Option[Account]
+  )(repositoryOwnerName: Username, repositoryName: VcsRepositoryName): F[Option[(VcsRepository, Long)]] =
+    for {
+      owner <- vcsMetadataRepo.findVcsRepositoryOwner(repositoryOwnerName)
+      loadedRepo <- owner match {
+        case None => Sync[F].pure(None)
+        case Some(owner) =>
+          (
+            vcsMetadataRepo.findVcsRepository(owner, repositoryName),
+            vcsMetadataRepo.findVcsRepositoryId(owner, repositoryName)
+          ).mapN {
+            case (Some(repo), Some(repoId)) => (repo, repoId).some
+            case _                          => None
+          }
+      }
+      // TODO Replace with whatever we implement as proper permission model. ;-)
+      repoAndId = currentUser match {
+        case None => loadedRepo.filter(tuple => tuple._1.isPrivate === false)
+        case Some(user) =>
+          loadedRepo.filter(tuple => tuple._1.isPrivate === false || tuple._1.owner === user.toVcsRepositoryOwner)
+      }
+    } yield repoAndId
+
   /** Delete the given directory recursively. It is checked if the given directory is a direct sub directory of the
     * owner's directory under `repositoriesDirectory` and only if this is the case is the directory removed.
     *
@@ -150,17 +187,8 @@
       user: Option[Account]
   )(repositoryOwnerName: Username, repositoryName: VcsRepositoryName): F[Option[fs2.io.file.Path]] =
     for {
-      owner <- vcsMetadataRepo.findVcsRepositoryOwner(repositoryOwnerName)
-      loadedRepo <- owner match {
-        case None        => Sync[F].pure(None)
-        case Some(owner) => vcsMetadataRepo.findVcsRepository(owner, repositoryName)
-      }
-      // TODO Replace with whatever we implement as proper permission model. ;-)
-      repo = user match {
-        case None => loadedRepo.filter(r => r.isPrivate === false)
-        case Some(user) =>
-          loadedRepo.filter(r => r.isPrivate === false || r.owner === user.toVcsRepositoryOwner)
-      }
+      repoAndId <- loadRepo(user)(repositoryOwnerName, repositoryName)
+      repo = repoAndId.map(_._1)
       repositoryOwnerDirectory <- Sync[F].delay(
         os.Path(
           Paths.get(
@@ -276,17 +304,8 @@
       csrf: Option[CsrfToken]
   )(user: Option[Account])(repositoryOwnerName: Username, repositoryName: VcsRepositoryName): F[Response[F]] =
     for {
-      owner <- vcsMetadataRepo.findVcsRepositoryOwner(repositoryOwnerName)
-      loadedRepo <- owner match {
-        case None        => Sync[F].pure(None)
-        case Some(owner) => vcsMetadataRepo.findVcsRepository(owner, repositoryName)
-      }
-      // TODO Replace with whatever we implement as proper permission model. ;-)
-      repo = user match {
-        case None => loadedRepo.filter(r => r.isPrivate === false)
-        case Some(user) =>
-          loadedRepo.filter(r => r.isPrivate === false || r.owner === user.toVcsRepositoryOwner)
-      }
+      repoAndId <- loadRepo(user)(repositoryOwnerName, repositoryName)
+      repo = repoAndId.map(_._1)
       actionBaseUri <- Sync[F].delay(
         linkConfig.createFullUri(
           Uri(path =
@@ -372,17 +391,8 @@
       user: Option[Account]
   )(repositoryOwnerName: Username, repositoryName: VcsRepositoryName)(filePath: Uri.Path): F[Response[F]] =
     for {
-      owner <- vcsMetadataRepo.findVcsRepositoryOwner(repositoryOwnerName)
-      loadedRepo <- owner match {
-        case None        => Sync[F].pure(None)
-        case Some(owner) => vcsMetadataRepo.findVcsRepository(owner, repositoryName)
-      }
-      // TODO Replace with whatever we implement as proper permission model. ;-)
-      repo = user match {
-        case None => loadedRepo.filter(r => r.isPrivate === false)
-        case Some(user) =>
-          loadedRepo.filter(r => r.isPrivate === false || r.owner === user.toVcsRepositoryOwner)
-      }
+      repoAndId <- loadRepo(user)(repositoryOwnerName, repositoryName)
+      repo = repoAndId.map(_._1)
       requestedFilePath <- repo
         .traverse(_ =>
           Sync[F].delay(
@@ -491,17 +501,8 @@
       fromEntry: Option[Int]
   ): F[Response[F]] =
     for {
-      owner <- vcsMetadataRepo.findVcsRepositoryOwner(repositoryOwnerName)
-      loadedRepo <- owner match {
-        case None        => Sync[F].pure(None)
-        case Some(owner) => vcsMetadataRepo.findVcsRepository(owner, repositoryName)
-      }
-      // TODO Replace with whatever we implement as proper permission model. ;-)
-      repo = user match {
-        case None => loadedRepo.filter(r => r.isPrivate === false)
-        case Some(user) =>
-          loadedRepo.filter(r => r.isPrivate === false || r.owner === user.toVcsRepositoryOwner)
-      }
+      repoAndId <- loadRepo(user)(repositoryOwnerName, repositoryName)
+      repo = repoAndId.map(_._1)
       directory <- Sync[F].delay(
         os.Path(
           Paths.get(
@@ -589,17 +590,8 @@
       user: Option[Account]
   )(repositoryOwnerName: Username, repositoryName: VcsRepositoryName)(hash: DarcsHash): F[Response[F]] =
     for {
-      owner <- vcsMetadataRepo.findVcsRepositoryOwner(repositoryOwnerName)
-      loadedRepo <- owner match {
-        case None        => Sync[F].pure(None)
-        case Some(owner) => vcsMetadataRepo.findVcsRepository(owner, repositoryName)
-      }
-      // TODO Replace with whatever we implement as proper permission model. ;-)
-      repo = user match {
-        case None => loadedRepo.filter(r => r.isPrivate === false)
-        case Some(user) =>
-          loadedRepo.filter(r => r.isPrivate === false || r.owner === user.toVcsRepositoryOwner)
-      }
+      repoAndId <- loadRepo(user)(repositoryOwnerName, repositoryName)
+      repo = repoAndId.map(_._1)
       directory <- Sync[F].delay(
         os.Path(
           Paths.get(
@@ -771,14 +763,9 @@
         ) / "fork" as user =>
       ar.req.decodeStrict[F, UrlForm] { urlForm =>
         for {
-          csrf  <- Sync[F].delay(ar.req.getCsrfToken)
-          owner <- vcsMetadataRepo.findVcsRepositoryOwner(repositoryOwnerName)
-          loadedSourceRepo <- owner match {
-            case None        => Sync[F].pure(None)
-            case Some(owner) => vcsMetadataRepo.findVcsRepository(owner, repositoryName)
-          }
-          // TODO Replace with whatever we implement as proper permission model. ;-)
-          sourceRepository = loadedSourceRepo.filter(r => r.isPrivate === false)
+          csrf      <- Sync[F].delay(ar.req.getCsrfToken)
+          repoAndId <- loadRepo(user.some)(repositoryOwnerName, repositoryName)
+          sourceRepository = repoAndId.map(_._1)
           // Check if a repository with that name already exists for the user.
           loadedTargetRepo <- vcsMetadataRepo.findVcsRepository(user.toVcsRepositoryOwner, repositoryName)
           // If no repo exists we copy and adjust the source one, otherwise we return `None`.
@@ -983,13 +970,8 @@
               "An unvalidated account is not allowed to edit a repository!"
             ) // FIXME Proper error handling!
           )
-          owner <- vcsMetadataRepo.findVcsRepositoryOwner(repositoryOwnerName)
-          loadedRepo <- owner match {
-            case None        => Sync[F].pure(None)
-            case Some(owner) => vcsMetadataRepo.findVcsRepository(owner, repositoryName)
-          }
-          // TODO Replace with whatever we implement as proper permission model. ;-)
-          repo = loadedRepo.filter(r => r.isPrivate === false || r.owner === user.toVcsRepositoryOwner)
+          repoAndId <- loadRepo(user.some)(repositoryOwnerName, repositoryName)
+          repo = repoAndId.map(_._1)
           resp <- repo match {
             case None => NotFound()
             case Some(repo) =>
@@ -1096,14 +1078,9 @@
           repositoryName
         ) / "delete" as user =>
       for {
-        csrf  <- Sync[F].delay(ar.req.getCsrfToken)
-        owner <- vcsMetadataRepo.findVcsRepositoryOwner(repositoryOwnerName)
-        loadedRepo <- owner match {
-          case None        => Sync[F].pure(None)
-          case Some(owner) => vcsMetadataRepo.findVcsRepository(owner, repositoryName)
-        }
-        // TODO Replace with whatever we implement as proper permission model. ;-)
-        repo = loadedRepo.filter(r => r.isPrivate === false || r.owner === user.toVcsRepositoryOwner)
+        csrf      <- Sync[F].delay(ar.req.getCsrfToken)
+        repoAndId <- loadRepo(user.some)(repositoryOwnerName, repositoryName)
+        repo = repoAndId.map(_._1)
         deleteAction <- Sync[F].delay(
           linkConfig.createFullUri(
             Uri(path =
@@ -1151,14 +1128,9 @@
           repositoryName
         ) / "edit" as user =>
       for {
-        csrf  <- Sync[F].delay(ar.req.getCsrfToken)
-        owner <- vcsMetadataRepo.findVcsRepositoryOwner(repositoryOwnerName)
-        loadedRepo <- owner match {
-          case None        => Sync[F].pure(None)
-          case Some(owner) => vcsMetadataRepo.findVcsRepository(owner, repositoryName)
-        }
-        // TODO Replace with whatever we implement as proper permission model. ;-)
-        repo = loadedRepo.filter(r => r.isPrivate === false || r.owner === user.toVcsRepositoryOwner)
+        csrf      <- Sync[F].delay(ar.req.getCsrfToken)
+        repoAndId <- loadRepo(user.some)(repositoryOwnerName, repositoryName)
+        repo = repoAndId.map(_._1)
         editAction <- Sync[F].delay(
           linkConfig.createFullUri(
             Uri(path =