mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-10-29 01:26:23 +01:00
205 lines
7.2 KiB
Scala
205 lines
7.2 KiB
Scala
package app
|
|
|
|
import _root_.util.Directory._
|
|
import _root_.util.Implicits._
|
|
import _root_.util.ControlUtil._
|
|
import _root_.util.{StringUtil, FileUtil, Validations, Keys}
|
|
import org.scalatra._
|
|
import org.scalatra.json._
|
|
import org.json4s._
|
|
import jp.sf.amateras.scalatra.forms._
|
|
import org.apache.commons.io.FileUtils
|
|
import model.Account
|
|
import service.{SystemSettingsService, AccountService}
|
|
import javax.servlet.http.{HttpServletResponse, HttpSession, HttpServletRequest}
|
|
import java.text.SimpleDateFormat
|
|
import javax.servlet.{FilterChain, ServletResponse, ServletRequest}
|
|
import org.scalatra.i18n._
|
|
|
|
/**
|
|
* Provides generic features for controller implementations.
|
|
*/
|
|
abstract class ControllerBase extends ScalatraFilter
|
|
with ClientSideValidationFormSupport with JacksonJsonSupport with I18nSupport with FlashMapSupport with Validations
|
|
with SystemSettingsService {
|
|
|
|
implicit val jsonFormats = DefaultFormats
|
|
|
|
// Don't set content type via Accept header.
|
|
override def format(implicit request: HttpServletRequest) = ""
|
|
|
|
override def doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
|
|
val httpRequest = request.asInstanceOf[HttpServletRequest]
|
|
val httpResponse = response.asInstanceOf[HttpServletResponse]
|
|
val context = request.getServletContext.getContextPath
|
|
val path = httpRequest.getRequestURI.substring(context.length)
|
|
|
|
if(path.startsWith("/console/")){
|
|
val account = httpRequest.getSession.getAttribute(Keys.Session.LoginAccount).asInstanceOf[Account]
|
|
if(account == null){
|
|
// Redirect to login form
|
|
httpResponse.sendRedirect(context + "/signin?" + StringUtil.urlEncode(path))
|
|
} else if(account.isAdmin){
|
|
// H2 Console (administrators only)
|
|
chain.doFilter(request, response)
|
|
} else {
|
|
// Redirect to dashboard
|
|
httpResponse.sendRedirect(context + "/")
|
|
}
|
|
} else if(path.startsWith("/git/")){
|
|
// Git repository
|
|
chain.doFilter(request, response)
|
|
} else {
|
|
// Scalatra actions
|
|
super.doFilter(request, response, chain)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the context object for the request.
|
|
*/
|
|
implicit def context: Context = Context(servletContext.getContextPath, LoginAccount, request)
|
|
|
|
private def LoginAccount: Option[Account] = session.getAs[Account](Keys.Session.LoginAccount)
|
|
|
|
def ajaxGet(path : String)(action : => Any) : Route =
|
|
super.get(path){
|
|
request.setAttribute(Keys.Request.Ajax, "true")
|
|
action
|
|
}
|
|
|
|
override def ajaxGet[T](path : String, form : ValueType[T])(action : T => Any) : Route =
|
|
super.ajaxGet(path, form){ form =>
|
|
request.setAttribute(Keys.Request.Ajax, "true")
|
|
action(form)
|
|
}
|
|
|
|
def ajaxPost(path : String)(action : => Any) : Route =
|
|
super.post(path){
|
|
request.setAttribute(Keys.Request.Ajax, "true")
|
|
action
|
|
}
|
|
|
|
override def ajaxPost[T](path : String, form : ValueType[T])(action : T => Any) : Route =
|
|
super.ajaxPost(path, form){ form =>
|
|
request.setAttribute(Keys.Request.Ajax, "true")
|
|
action(form)
|
|
}
|
|
|
|
protected def NotFound() =
|
|
if(request.hasAttribute(Keys.Request.Ajax)){
|
|
org.scalatra.NotFound()
|
|
} else {
|
|
org.scalatra.NotFound(html.error("Not Found"))
|
|
}
|
|
|
|
protected def Unauthorized()(implicit context: app.Context) =
|
|
if(request.hasAttribute(Keys.Request.Ajax)){
|
|
org.scalatra.Unauthorized()
|
|
} else {
|
|
if(context.loginAccount.isDefined){
|
|
org.scalatra.Unauthorized(redirect("/"))
|
|
} else {
|
|
if(request.getMethod.toUpperCase == "POST"){
|
|
org.scalatra.Unauthorized(redirect("/signin"))
|
|
} else {
|
|
org.scalatra.Unauthorized(redirect("/signin?redirect=" + StringUtil.urlEncode(
|
|
defining(request.getQueryString){ queryString =>
|
|
request.getRequestURI.substring(request.getContextPath.length) + (if(queryString != null) "?" + queryString else "")
|
|
}
|
|
)))
|
|
}
|
|
}
|
|
}
|
|
|
|
override def fullUrl(path: String, params: Iterable[(String, Any)] = Iterable.empty,
|
|
includeContextPath: Boolean = true, includeServletPath: Boolean = true)
|
|
(implicit request: HttpServletRequest, response: HttpServletResponse) =
|
|
if (path.startsWith("http")) path
|
|
else baseUrl + url(path, params, false, false)
|
|
|
|
}
|
|
|
|
/**
|
|
* Context object for the current request.
|
|
*/
|
|
case class Context(path: String, loginAccount: Option[Account], request: HttpServletRequest){
|
|
|
|
/**
|
|
* Get object from cache.
|
|
*
|
|
* If object has not been cached with the specified key then retrieves by given action.
|
|
* Cached object are available during a request.
|
|
*/
|
|
def cache[A](key: String)(action: => A): A =
|
|
defining(Keys.Request.Cache(key)){ cacheKey =>
|
|
Option(request.getAttribute(cacheKey).asInstanceOf[A]).getOrElse {
|
|
val newObject = action
|
|
request.setAttribute(cacheKey, newObject)
|
|
newObject
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Base trait for controllers which manages account information.
|
|
*/
|
|
trait AccountManagementControllerBase extends ControllerBase with FileUploadControllerBase {
|
|
self: AccountService =>
|
|
|
|
protected def updateImage(userName: String, fileId: Option[String], clearImage: Boolean): Unit =
|
|
if(clearImage){
|
|
getAccountByUserName(userName).flatMap(_.image).map { image =>
|
|
new java.io.File(getUserUploadDir(userName), image).delete()
|
|
updateAvatarImage(userName, None)
|
|
}
|
|
} else {
|
|
fileId.map { fileId =>
|
|
val filename = "avatar." + FileUtil.getExtension(getUploadedFilename(fileId).get)
|
|
FileUtils.moveFile(
|
|
getTemporaryFile(fileId),
|
|
new java.io.File(getUserUploadDir(userName), filename)
|
|
)
|
|
updateAvatarImage(userName, Some(filename))
|
|
}
|
|
}
|
|
|
|
protected def uniqueUserName: Constraint = new Constraint(){
|
|
override def validate(name: String, value: String, messages: Messages): Option[String] =
|
|
getAccountByUserName(value, true).map { _ => "User already exists." }
|
|
}
|
|
|
|
protected def uniqueMailAddress(paramName: String = ""): Constraint = new Constraint(){
|
|
override def validate(name: String, value: String, params: Map[String, String], messages: Messages): Option[String] =
|
|
getAccountByMailAddress(value, true)
|
|
.filter { x => if(paramName.isEmpty) true else Some(x.userName) != params.get(paramName) }
|
|
.map { _ => "Mail address is already registered." }
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Base trait for controllers which needs file uploading feature.
|
|
*/
|
|
trait FileUploadControllerBase {
|
|
|
|
def generateFileId: String =
|
|
new SimpleDateFormat("yyyyMMddHHmmSSsss").format(new java.util.Date(System.currentTimeMillis))
|
|
|
|
def TemporaryDir(implicit session: HttpSession): java.io.File =
|
|
new java.io.File(GitBucketHome, s"tmp/_upload/${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 getUploadedFilename(fileId: String)(implicit session: HttpSession): Option[String] =
|
|
session.getAndRemove[String](Keys.Session.Upload(fileId))
|
|
|
|
} |