~jan0sch/smederee
Showing details for patch 731a0117556ac2e26066eb52c1839d7c3bc71d95.
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-02-02 14:39:17.086094661 +0000 +++ new-smederee/modules/hub/src/main/scala/de/smederee/hub/VcsRepositoryRoutes.scala 2025-02-02 14:39:17.086094661 +0000 @@ -348,6 +348,39 @@ Sync[F].delay(IndexedSeq.empty) } yield listing + private val cloneRepository: HttpRoutes[F] = HttpRoutes.of { + case req @ GET -> UsernamePathParameter(repositoryOwnerName) /: VcsRepositoryClonePathParameter( + repositoryName + ) /: filePath => + for { + csrf <- Sync[F].delay(req.getCsrfToken) + owner <- vcsMetadataRepo.findVcsRepositoryOwner(repositoryOwnerName) + loadedRepo <- owner match { + case None => Sync[F].pure(None) + case Some(owner) => vcsMetadataRepo.findVcsRepository(owner, repositoryName) + } + // Cloning via HTTP protocol is public only, so we don't need more sophisticated checks here. + repo = loadedRepo.filter(r => r.isPrivate === false) + requestedFilePath <- Sync[F].delay( + repo.map(_ => + fs2.io.file.Path.fromNioPath( + Paths.get( + config.repositoriesDirectory.toPath.toString, + repositoryOwnerName.toString, + repositoryName.toString, + filePath.segments.mkString("/") + ) + ) + ) + ) + _ <- Sync[F].delay(log.info(s"Repository $repo ($requestedFilePath) is cloned.")) + resp <- (repo, requestedFilePath) match { + case (Some(repo), Some(path)) => StaticFile.fromPath(path, req.some).getOrElseF(NotFound()) + case _ => NotFound() + } + } yield resp + } + private val parseCreateRepositoryForm: AuthedRoutes[Account, F] = AuthedRoutes.of { case ar @ POST -> Root / "repo" / "create" as user => ar.req.decodeStrict[F, UrlForm] { urlForm => @@ -563,8 +596,22 @@ showAllRepositories <+> showRepositories <+> parseCreateRepositoryForm <+> showCreateRepositoryForm <+> showRepositoryOverview <+> showRepositoryHistory <+> showRepositoryFiles val routes = - showAllRepositoriesForGuests <+> showRepositoryOverviewForGuests <+> showRepositoryHistoryForGuests <+> showRepositoryFilesForGuests + cloneRepository <+> showAllRepositoriesForGuests <+> showRepositoryOverviewForGuests <+> showRepositoryHistoryForGuests <+> showRepositoryFilesForGuests } +/** Extractor for an optional query parameter we use in our history route. + */ object HistoryFromQueryParameter extends OptionalQueryParamDecoderMatcher[Int]("from") + +/** A path parameter extractor to get the vcs repository name for a clone operation. + */ +object VcsRepositoryClonePathParameter { + def unapply(str: String): Option[VcsRepositoryName] = + Option(str).flatMap { string => + if (string.endsWith(".darcs")) + VcsRepositoryName.from(string.reverse.drop(6).reverse) + else + None + } +}