All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gitbucket.core.controller.ReleasesController.scala Maven / Gradle / Ivy

The newest version!
package gitbucket.core.controller

import java.io.File

import gitbucket.core.model.activity.ReleaseInfo
import gitbucket.core.service.{
  AccountService,
  ActivityService,
  PaginationHelper,
  ReleaseService,
  RepositoryService,
  RequestCache
}
import gitbucket.core.util._
import gitbucket.core.util.Directory._
import gitbucket.core.util.Implicits._
import org.scalatra.forms._
import gitbucket.core.releases.html
import org.apache.commons.io.FileUtils
import org.eclipse.jgit.api.Git

import scala.util.Using

class ReleaseController
    extends ReleaseControllerBase
    with RepositoryService
    with AccountService
    with ReleaseService
    with ActivityService
    with ReadableUsersAuthenticator
    with ReferrerAuthenticator
    with WritableUsersAuthenticator
    with RequestCache

trait ReleaseControllerBase extends ControllerBase {
  self: RepositoryService
    with AccountService
    with ReleaseService
    with ReadableUsersAuthenticator
    with ReferrerAuthenticator
    with WritableUsersAuthenticator
    with ActivityService =>

  case class ReleaseForm(
    name: String,
    content: Option[String]
  )

  val releaseForm = mapping(
    "name" -> trim(text(required)),
    "content" -> trim(optional(text()))
  )(ReleaseForm.apply)

  get("/:owner/:repository/releases")(referrersOnly { repository =>
    val page = PaginationHelper.page(params.get("page"))

    html.list(
      repository,
      fetchReleases(repository, page),
      hasDeveloperRole(repository.owner, repository.name, context.loginAccount),
      page,
      repository.tags.size
    )
  })

  get("/:owner/:repository/releases/*")(referrersOnly { repository =>
    val tagName = multiParams("splat").head
    getRelease(repository.owner, repository.name, tagName)
      .map { release =>
        html.release(
          release,
          getReleaseAssets(repository.owner, repository.name, tagName),
          hasDeveloperRole(repository.owner, repository.name, context.loginAccount),
          repository
        )
      }
      .getOrElse(NotFound())
  })

  get("/:owner/:repository/releases/*/assets/:fileId")(referrersOnly { repository =>
    val tagName = multiParams("splat").head
    val fileId = params("fileId")
    (for {
      _ <- repository.tags.find(_.name == tagName)
      _ <- getRelease(repository.owner, repository.name, tagName)
      asset <- getReleaseAsset(repository.owner, repository.name, tagName, fileId)
    } yield {
      response.setHeader("Content-Disposition", s"attachment; filename=${asset.label}")
      RawData(
        FileUtil.getSafeMimeType(asset.label),
        new File(getReleaseFilesDir(repository.owner, repository.name), FileUtil.checkFilename(tagName + "/" + fileId))
      )
    }).getOrElse(NotFound())
  })

  get("/:owner/:repository/releases/*/create")(writableUsersOnly { repository =>
    val tagName = multiParams("splat").head
    val previousTags = repository.tags.takeWhile(_.name != tagName).reverse

    repository.tags
      .find(_.name == tagName)
      .map { tag =>
        html.form(repository, tag, previousTags.map(_.name), tag.message, None)
      }
      .getOrElse(NotFound())
  })

  post("/:owner/:repository/releases/*/create", releaseForm)(writableUsersOnly { (form, repository) =>
    context.withLoginAccount { loginAccount =>
      val tagName = multiParams("splat").head

      // Insert into RELEASE
      createRelease(repository.owner, repository.name, form.name, form.content, tagName, loginAccount)

      // Insert into RELEASE_ASSET
      val files = params.toMap.collect {
        case (name, value) if name.startsWith("file:") =>
          val Array(_, fileId) = name.split(":")
          (fileId, value)
      }
      files.foreach { case (fileId, fileName) =>
        val size =
          new File(
            getReleaseFilesDir(repository.owner, repository.name),
            FileUtil.checkFilename(tagName + "/" + fileId)
          ).length
        createReleaseAsset(repository.owner, repository.name, tagName, fileId, fileName, size, loginAccount)
      }

      val releaseInfo = ReleaseInfo(repository.owner, repository.name, loginAccount.userName, form.name, tagName)
      recordActivity(releaseInfo)

      redirect(s"/${repository.owner}/${repository.name}/releases/${tagName}")
    }
  })

  get("/:owner/:repository/changelog/*...*")(writableUsersOnly { repository =>
    val Seq(previousTag, currentTag) = multiParams("splat")
    val previousTagId = repository.tags.collectFirst { case x if x.name == previousTag => x.commitId }.getOrElse("")

    val commitLog = Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
      val commits = JGitUtil.getCommitLog(git, previousTagId, currentTag).reverse
      commits
        .map { commit =>
          s"- ${commit.shortMessage} ${commit.id}"
        }
        .mkString("\n")
    }

    commitLog
  })

  get("/:owner/:repository/releases/*/edit")(writableUsersOnly { repository =>
    val tagName = multiParams("splat").head
    val previousTags = repository.tags.takeWhile(_.name != tagName).reverse

    (for {
      release <- getRelease(repository.owner, repository.name, tagName)
      tag <- repository.tags.find(_.name == tagName)
    } yield {
      html.form(
        repository,
        tag,
        previousTags.map(_.name),
        release.content.getOrElse(""),
        Some(release, getReleaseAssets(repository.owner, repository.name, tagName))
      )
    }).getOrElse(NotFound())
  })

  post("/:owner/:repository/releases/*/edit", releaseForm)(writableUsersOnly { (form, repository) =>
    context.withLoginAccount { loginAccount =>
      val tagName = multiParams("splat").head

      getRelease(repository.owner, repository.name, tagName)
        .map { release =>
          // Update RELEASE
          updateRelease(repository.owner, repository.name, tagName, form.name, form.content)

          // Delete and Insert RELEASE_ASSET
          val assets = getReleaseAssets(repository.owner, repository.name, tagName)
          deleteReleaseAssets(repository.owner, repository.name, tagName)

          val files = params.toMap.collect {
            case (name, value) if name.startsWith("file:") =>
              val Array(_, fileId) = name.split(":")
              (fileId, value)
          }
          files.foreach { case (fileId, fileName) =>
            val size =
              new File(
                getReleaseFilesDir(repository.owner, repository.name),
                FileUtil.checkFilename(tagName + "/" + fileId)
              ).length
            createReleaseAsset(repository.owner, repository.name, tagName, fileId, fileName, size, loginAccount)
          }

          assets.foreach { asset =>
            if (!files.exists { case (fileId, _) => fileId == asset.fileName }) {
              val file = new File(
                getReleaseFilesDir(repository.owner, repository.name),
                FileUtil.checkFilename(release.tag + "/" + asset.fileName)
              )
              FileUtils.forceDelete(file)
            }
          }

          redirect(s"/${release.userName}/${release.repositoryName}/releases/${tagName}")
        }
        .getOrElse(NotFound())
    }
  })

  post("/:owner/:repository/releases/*/delete")(writableUsersOnly { repository =>
    val tagName = multiParams("splat").head
    getRelease(repository.owner, repository.name, tagName).foreach { release =>
      FileUtils.deleteDirectory(
        new File(getReleaseFilesDir(repository.owner, repository.name), FileUtil.checkFilename(release.tag))
      )
    }
    deleteRelease(repository.owner, repository.name, tagName)
    redirect(s"/${repository.owner}/${repository.name}/releases")
  })

  private def fetchReleases(repository: RepositoryService.RepositoryInfo, page: Int) = {
    import gitbucket.core.service.ReleaseService._

    val (offset, limit) = ((page - 1) * ReleaseLimit, ReleaseLimit)
    val tagsToDisplay = repository.tags.reverse.slice(offset, offset + limit)

    val releases = getReleases(repository.owner, repository.name, tagsToDisplay)
    val assets = getReleaseAssetsMap(repository.owner, repository.name, releases)

    val tagsWithReleases = tagsToDisplay.map { tag =>
      (
        tag,
        releases.find(_.tag == tag.name).map { release =>
          (release, assets(release))
        }
      )
    }
    tagsWithReleases
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy