diff --git a/src/main/resources/update/1_3.sql b/src/main/resources/update/1_3.sql new file mode 100644 index 0000000..8001b9e --- /dev/null +++ b/src/main/resources/update/1_3.sql @@ -0,0 +1 @@ +ALTER TABLE ACCOUNT ADD COLUMN IMAGE VARCHAR(100); diff --git a/src/main/scala/app/AccountController.scala b/src/main/scala/app/AccountController.scala index de5ed9c..c657e4a 100644 --- a/src/main/scala/app/AccountController.scala +++ b/src/main/scala/app/AccountController.scala @@ -3,7 +3,9 @@ import service._ import util.OneselfAuthenticator import util.StringUtil._ +import util.Directory._ import jp.sf.amateras.scalatra.forms._ +import org.apache.commons.io.FileSystemUtils class AccountController extends AccountControllerBase with SystemSettingsService with AccountService with RepositoryService with ActivityService @@ -15,7 +17,7 @@ case class AccountNewForm(userName: String, password: String,mailAddress: String, url: Option[String]) - case class AccountEditForm(password: Option[String], mailAddress: String, url: Option[String]) + case class AccountEditForm(password: Option[String], mailAddress: String, url: Option[String], fileId: Option[String]) val newForm = mapping( "userName" -> trim(label("User name" , text(required, maxlength(100), identifier, uniqueUserName))), @@ -27,7 +29,8 @@ val editForm = mapping( "password" -> trim(label("Password" , optional(text(maxlength(20))))), "mailAddress" -> trim(label("Mail Address" , text(required, maxlength(100), uniqueMailAddress("userName")))), - "url" -> trim(label("URL" , optional(text(maxlength(200))))) + "url" -> trim(label("URL" , optional(text(maxlength(200))))), + "fileId" -> trim(label("File ID" , optional(text()))) )(AccountEditForm.apply) /** @@ -57,6 +60,16 @@ password = form.password.map(encrypt).getOrElse(account.password), mailAddress = form.mailAddress, url = form.url)) + + form.fileId.map { fileId => + val filename = app.FileUploadUtil.getFilename(fileId) + org.apache.commons.io.FileUtils.moveFile( + app.FileUploadUtil.getTemporaryFile(fileId), + new java.io.File(getUserUploadDir(userName), filename.get) + ) + updateAvatarImage(userName, filename) + } + redirect("/%s".format(userName)) } getOrElse NotFound }) diff --git a/src/main/scala/app/FileUploadController.scala b/src/main/scala/app/FileUploadController.scala index f3e3ed9..4775769 100644 --- a/src/main/scala/app/FileUploadController.scala +++ b/src/main/scala/app/FileUploadController.scala @@ -1,7 +1,11 @@ package app +import util.Directory._ import org.scalatra._ import org.scalatra.servlet.{MultipartConfig, FileUploadSupport} +import java.text.SimpleDateFormat +import org.apache.commons.io.FileUtils +import javax.servlet.http.HttpSession /** * Provides Ajax based file upload functionality. @@ -11,15 +15,15 @@ */ // TODO Remove temporary files at session timeout by session listener. class FileUploadController extends ScalatraServlet with FileUploadSupport with FlashMapSupport { - configureMultipartHandling(MultipartConfig(maxFileSize = Some(3*1024*1024))) + configureMultipartHandling(MultipartConfig(maxFileSize = Some(3 * 1024 * 1024))) post("/"){ fileParams.get("file") match { - // TODO save as temporary file and return key. case Some(file) => { - println(file.name) - println(file.size) - Ok("1234") + val fileId = new SimpleDateFormat("yyyyMMddHHmmSSsss").format(new java.util.Date(System.currentTimeMillis)) + FileUtils.writeByteArrayToFile(FileUploadUtil.getTemporaryFile(fileId), file.get) + session += "fileId" -> file.name + Ok(fileId) } case None => BadRequest } @@ -27,10 +31,28 @@ } -// TODO Not implemented yet. +// TODO move to other package or should be trait? object FileUploadUtil { - def getFile(key: String) = { + def TemporaryDir(implicit session: HttpSession): java.io.File = + new java.io.File(GitBucketHome, "tmp/_%s".format(session.getId)) + + def getTemporaryFile(fileId: String)(implicit session: HttpSession): java.io.File = + new java.io.File(TemporaryDir, fileId) + + def removeTemporaryFile(fileId: String)(implicit session: HttpSession): Unit = + getTemporaryFile(fileId).delete() + + def removeTemporaryFiles()(implicit session: HttpSession): Unit = + FileUtils.deleteDirectory(TemporaryDir) + + def getFilename(fileId: String)(implicit session: HttpSession): Option[String] = { + val filename = Option(session.getAttribute(fileId).asInstanceOf[String]) + if(filename.isDefined){ + session.removeAttribute(fileId) + } + filename } + } diff --git a/src/main/scala/model/Account.scala b/src/main/scala/model/Account.scala index 84661c4..d0f1f59 100644 --- a/src/main/scala/model/Account.scala +++ b/src/main/scala/model/Account.scala @@ -11,7 +11,8 @@ def registeredDate = column[java.util.Date]("REGISTERED_DATE") def updatedDate = column[java.util.Date]("UPDATED_DATE") def lastLoginDate = column[java.util.Date]("LAST_LOGIN_DATE") - def * = userName ~ mailAddress ~ password ~ isAdmin ~ url.? ~ registeredDate ~ updatedDate ~ lastLoginDate.? <> (Account, Account.unapply _) + def image = column[String]("IMAGE") + def * = userName ~ mailAddress ~ password ~ isAdmin ~ url.? ~ registeredDate ~ updatedDate ~ lastLoginDate.? ~ image.? <> (Account, Account.unapply _) } case class Account( @@ -22,5 +23,6 @@ url: Option[String], registeredDate: java.util.Date, updatedDate: java.util.Date, - lastLoginDate: Option[java.util.Date] + lastLoginDate: Option[java.util.Date], + image: Option[String] ) diff --git a/src/main/scala/service/AccountService.scala b/src/main/scala/service/AccountService.scala index 9111cd9..28223e1 100644 --- a/src/main/scala/service/AccountService.scala +++ b/src/main/scala/service/AccountService.scala @@ -23,7 +23,8 @@ url = url, registeredDate = currentDate, updatedDate = currentDate, - lastLoginDate = None) + lastLoginDate = None, + image = None) def updateAccount(account: Account): Unit = Accounts @@ -37,7 +38,10 @@ account.registeredDate, currentDate, account.lastLoginDate) - + + def updateAvatarImage(userName: String, image: Option[String]): Unit = + Accounts.filter(_.userName is userName.bind).map(_.image.?).update(image) + def updateLastLoginDate(userName: String): Unit = Accounts.filter(_.userName is userName.bind).map(_.lastLoginDate).update(currentDate) diff --git a/src/main/scala/servlet/AutoUpdateListener.scala b/src/main/scala/servlet/AutoUpdateListener.scala index 46e8364..266e617 100644 --- a/src/main/scala/servlet/AutoUpdateListener.scala +++ b/src/main/scala/servlet/AutoUpdateListener.scala @@ -49,6 +49,7 @@ * The history of versions. A head of this sequence is the current BitBucket version. */ val versions = Seq( + Version(1, 3), Version(1, 2), Version(1, 1), Version(1, 0) diff --git a/src/main/scala/util/Directory.scala b/src/main/scala/util/Directory.scala index 6742528..b76ebd2 100644 --- a/src/main/scala/util/Directory.scala +++ b/src/main/scala/util/Directory.scala @@ -36,6 +36,11 @@ new File("%s/%s/%s.git".format(RepositoryHome, owner, repository)) /** + * Directory for uploaded files by the specified user. + */ + def getUserUploadDir(userName: String): File = new File("%s/%s/_files".format(GitBucketHome, userName)) + + /** * Root of temporary directories for the specified repository. */ def getTemporaryDir(owner: String, repository: String): File = diff --git a/src/main/twirl/account/edit.scala.html b/src/main/twirl/account/edit.scala.html index 36aa731..dcde925 100644 --- a/src/main/twirl/account/edit.scala.html +++ b/src/main/twirl/account/edit.scala.html @@ -39,7 +39,7 @@
No Image
- +
@if(account.isDefined){ @@ -62,8 +62,10 @@ thumbnailHeight: 120 }); - dropzone.on("addedfile", function(){ + dropzone.on("success", function(file, id){ $('div#clickable').remove(); + $('input[name=fileId]').val(id); + alert(id); }); });