app/postrun/MakeAssetFolder.scala (93 lines of code) (raw):

package postrun import helpers.PostrunDataCache import models.{PlutoCommission, PlutoWorkingGroup, ProjectEntry, ProjectType} import org.slf4j.LoggerFactory import play.api.Configuration import java.nio.file.attribute.{PosixFileAttributeView, PosixFilePermissions} import java.nio.file.{FileSystems, Files, Path, Paths} import scala.concurrent.Future import scala.util.{Failure, Success, Try} import scala.concurrent.ExecutionContext.Implicits.global import cats.implicits._ class MakeAssetFolder(config:Configuration) extends PojoPostrun { private val logger = LoggerFactory.getLogger(getClass) private val sanitizer = "[^\\w\\d\\-]+".r /** * replaces any non-standard characters with _ to prevent weird issues and potential * security holes * @param pathPart section to sanitise * @return sanitised string */ protected def sanitize(pathPart:String) = sanitizer.replaceAllIn(pathPart,"_") /** * build a java.nio.Path representing the asset folder to create * @param workingGroupMaybe Optional PlutoWorkingGroup instance, operation fails if this is not set * @param commissionMaybe Optional PlutoCommission instance, operation fails if this is not set * @param projectEntry ProjectEntry instance * @return the asset folder path, or a Left with a descriptive error string */ protected def makeAssetFolderPath(workingGroupMaybe:Option[PlutoWorkingGroup], commissionMaybe:Option[PlutoCommission], projectEntry:ProjectEntry) = { (workingGroupMaybe, commissionMaybe, config.getOptional[String]("postrun.assetFolder.basePath")) match { case (Some(workingGroup), Some(commission), Some(basePath))=> val pathParts = Seq( basePath, sanitize(workingGroup.name), sanitize(commission.title), sanitize(s"${projectEntry.user}_${projectEntry.projectTitle}") ) Right(Paths.get(pathParts.head, (pathParts.tail):_*)) case (None,None,None)=> Left("Neither working group nor commission was set so asset folder path could not be created. You also need to set postrun.assetFolder.basePath in the configuration.") case (None, None, _)=> Left("Neither working group nor commission was set so asset folder path could not be created. ") case (_,_,None)=> Left("You need to set postrun.assetFolder.basePath in application.conf to the base path within which to create asset folders") case (None, _, _)=> Left("Working group was not set so asset folder path could not be created") case (_, None, _)=> Left("Commission was not set so asset folder path could not be created") } } /** * create the requested directory in the filesystem, with 755 permissions * @param dirPath java.nio.Path representing the directory to create * @return a Success with the directory path or Failure on error */ protected def doCreateDir(dirPath:Path) = Try { val attrs = PosixFilePermissions.asFileAttribute( PosixFilePermissions.fromString("rwxr-xr-x") ) Files.createDirectories(dirPath, attrs) } protected def findRequestedGroup = { config .getOptional[String]("postrun.assetFolder.owningGroup") .map(groupName=>Try { val lookup = FileSystems.getDefault.getUserPrincipalLookupService lookup.lookupPrincipalByGroupName(groupName) }) .sequence } /** * open the permissions on the end directory created to ensure that the user and group * can write to it * @param dirPath java.nio.Path representing the created asset folder * @return a Success with the directory path or Failure on error */ protected def setFinalDirPermissions(dirPath:Path) = Try { val perms = PosixFilePermissions.fromString("rwxrwxr-x") Files.setPosixFilePermissions(dirPath, perms) } /** * try to set the group ownership of the target directory, if a target group has been chosen in the configuration. * @param dirPath * @return */ protected def setFinalDirGroup(dirPath:Path) = findRequestedGroup match { case Success(Some(group))=>Try { logger.info(s"Updating group ownership of ${dirPath.toString} to ${group.getName}") val attrs = Files.getFileAttributeView(dirPath, classOf[PosixFileAttributeView]) attrs.setGroup(group) } case Success(None)=> logger.info(s"Not changing group ownership of ${dirPath.toString} because no group has been specified in the configuration") Success( () ) case Failure(err)=> logger.error(s"Could not change group ownership of ${dirPath.toString} to ${config.getOptional[String]("postrun.assetFolder.owningGroup")}: ${err.getMessage}",err) Failure(err) } override def postrun(projectFileName: String, projectEntry: ProjectEntry, projectType: ProjectType, dataCache: PostrunDataCache, workingGroupMaybe: Option[PlutoWorkingGroup], commissionMaybe: Option[PlutoCommission]): Future[Try[PostrunDataCache]] = Future { makeAssetFolderPath(workingGroupMaybe, commissionMaybe, projectEntry) match { case Left(problem)=> logger.error(s"$projectFileName: Could not build asset folder path: $problem") Failure(new RuntimeException("Could not build asset folder path")) case Right(assetFolderPath)=> logger.info(s"$projectFileName: Will create asset folder at $assetFolderPath") val creationResult = for { _ <- doCreateDir(assetFolderPath) finalPath <- setFinalDirPermissions(assetFolderPath) _ <- setFinalDirGroup(assetFolderPath) } yield finalPath creationResult.map(_=> { dataCache.withString("created_asset_folder",assetFolderPath.toString) }) } } }