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

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

The newest version!
package gitbucket.core.controller

import java.io.File

import gitbucket.core.model.Account
import gitbucket.core.service.{AccountService, ReleaseService, RepositoryService}
import gitbucket.core.servlet.Database
import gitbucket.core.util._
import gitbucket.core.util.Directory._
import gitbucket.core.util.Implicits._
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.dircache.DirCache
import org.eclipse.jgit.lib.{Constants, FileMode}
import org.scalatra._
import org.scalatra.servlet.{FileItem, FileUploadSupport, MultipartConfig}
import org.apache.commons.io.{FileUtils, IOUtils}

import scala.util.Using
import gitbucket.core.service.SystemSettingsService
import slick.jdbc.JdbcBackend.Session

/**
 * Provides Ajax based file upload functionality.
 *
 * This servlet saves uploaded file.
 */
class FileUploadController
    extends ScalatraServlet
    with FileUploadSupport
    with RepositoryService
    with AccountService
    with ReleaseService
    with SystemSettingsService {

  post("/image") {
    setMultipartConfig()
    execute(
      { (file, fileId) =>
        FileUtils
          .writeByteArrayToFile(new File(getTemporaryDir(session.getId), FileUtil.checkFilename(fileId)), file.get())
        session += Keys.Session.Upload(fileId) -> file.name
      },
      FileUtil.isImage(_)
    )
  }

  post("/tmp") {
    setMultipartConfig()
    execute(
      { (file, fileId) =>
        FileUtils
          .writeByteArrayToFile(new File(getTemporaryDir(session.getId), FileUtil.checkFilename(fileId)), file.get())
        session += Keys.Session.Upload(fileId) -> file.name
      },
      _ => true
    )
  }

  post("/file/:owner/:repository") {
    setMultipartConfig()
    execute(
      { (file, fileId) =>
        FileUtils.writeByteArrayToFile(
          new File(
            getAttachedDir(params("owner"), params("repository")),
            FileUtil.checkFilename(fileId + "." + FileUtil.getExtension(file.getName))
          ),
          file.get()
        )
      },
      _ => true
    )
  }

  post("/wiki/:owner/:repository") {
    setMultipartConfig()
    // Don't accept not logged-in users
    session.get(Keys.Session.LoginAccount).collect { case loginAccount: Account =>
      val owner = params("owner")
      val repository = params("repository")

      // Check whether logged-in user is collaborator
      onlyWikiEditable(owner, repository, loginAccount) {
        execute(
          { (file, fileId) =>
            val fileName = file.getName
            LockUtil.lock(s"${owner}/${repository}/wiki") {
              Using.resource(Git.open(Directory.getWikiRepositoryDir(owner, repository))) { git =>
                val builder = DirCache.newInCore.builder()
                val inserter = git.getRepository.newObjectInserter()
                val headId = git.getRepository.resolve(Constants.HEAD + "^{commit}")

                if (headId != null) {
                  JGitUtil.processTree(git, headId) { (path, tree) =>
                    if (path != fileName) {
                      builder.add(JGitUtil.createDirCacheEntry(path, tree.getEntryFileMode, tree.getEntryObjectId))
                    }
                  }
                }

                val bytes = IOUtils.toByteArray(file.getInputStream)
                builder.add(
                  JGitUtil.createDirCacheEntry(
                    fileName,
                    FileMode.REGULAR_FILE,
                    inserter.insert(Constants.OBJ_BLOB, bytes)
                  )
                )
                builder.finish()

                val newHeadId = JGitUtil.createNewCommit(
                  git,
                  inserter,
                  headId,
                  builder.getDirCache.writeTree(inserter),
                  Constants.HEAD,
                  loginAccount.fullName,
                  loginAccount.mailAddress,
                  s"Uploaded ${fileName}"
                )

                fileName
              }
            }
          },
          _ => true
        )
      }
    } getOrElse BadRequest()
  }

  post("/release/:owner/:repository/*") {
    setMultipartConfigForLargeFile()
    session
      .get(Keys.Session.LoginAccount)
      .collect { case _: Account =>
        val owner = params("owner")
        val repository = params("repository")
        val tag = multiParams("splat").head
        execute(
          { (file, fileId) =>
            FileUtils.writeByteArrayToFile(
              new File(getReleaseFilesDir(owner, repository), FileUtil.checkFilename(tag + "/" + fileId)),
              file.get()
            )
          },
          _ => true
        )
      }
      .getOrElse(BadRequest())
  }

  post("/import") {
    import JDBCUtil._
    setMultipartConfig()
    session.get(Keys.Session.LoginAccount).collect {
      case loginAccount: Account if loginAccount.isAdmin =>
        execute(
          { (file, fileId) =>
            request2Session(request).conn.importAsSQL(file.getInputStream)
          },
          _ => true
        )
    }
    redirect("/admin/data")
  }

  private def setMultipartConfig(): Unit = {
    val settings = loadSystemSettings()
    val config = MultipartConfig(maxFileSize = Some(settings.upload.maxFileSize))
    config.apply(request.getServletContext())
  }

  private def setMultipartConfigForLargeFile(): Unit = {
    val settings = loadSystemSettings()
    val config = MultipartConfig(maxFileSize = Some(settings.upload.largeMaxFileSize))
    config.apply(request.getServletContext())
  }

  private def onlyWikiEditable(owner: String, repository: String, loginAccount: Account)(action: => Any): Any = {
    implicit val session: Session = Database.getSession(request)
    getRepository(owner, repository) match {
      case Some(x) =>
        x.repository.options.wikiOption match {
          case "ALL" if !x.repository.isPrivate                                     => action
          case "PUBLIC" if hasGuestRole(owner, repository, Some(loginAccount))      => action
          case "PRIVATE" if hasDeveloperRole(owner, repository, Some(loginAccount)) => action
          case _                                                                    => BadRequest()
        }
      case None => BadRequest()
    }
  }

  private def execute(f: (FileItem, String) => Unit, mimeTypeChecker: (String) => Boolean) =
    fileParams.get("file") match {
      case Some(file) if mimeTypeChecker(file.name) =>
        val fileId = FileUtil.generateFileId
        f(file, fileId)
        contentType = "text/plain"
        Ok(fileId)
      case _ => BadRequest()
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy