Restructure settings UI (#2413)

This commit is contained in:
Naoki Takezoe
2020-01-13 02:28:30 +09:00
committed by GitHub
parent 6225fd79fc
commit 917b204e5b
14 changed files with 308 additions and 227 deletions

View File

@@ -41,12 +41,6 @@ public class JettyLauncher {
case "--prefix": case "--prefix":
contextPath = dim[1]; contextPath = dim[1];
break; break;
case "--max_file_size":
System.setProperty("gitbucket.maxFileSize", dim[1]);
break;
case "--upload_timeout":
System.setProperty("gitbucket.UploadTimeout", dim[1]);
break;
case "--gitbucket.home": case "--gitbucket.home":
System.setProperty("gitbucket.home", dim[1]); System.setProperty("gitbucket.home", dim[1]);
break; break;

View File

@@ -17,6 +17,7 @@ import org.scalatra.servlet.{FileItem, FileUploadSupport, MultipartConfig}
import org.apache.commons.io.{FileUtils, IOUtils} import org.apache.commons.io.{FileUtils, IOUtils}
import scala.util.Using import scala.util.Using
import gitbucket.core.service.SystemSettingsService
/** /**
* Provides Ajax based file upload functionality. * Provides Ajax based file upload functionality.
@@ -28,11 +29,11 @@ class FileUploadController
with FileUploadSupport with FileUploadSupport
with RepositoryService with RepositoryService
with AccountService with AccountService
with ReleaseService { with ReleaseService
with SystemSettingsService {
configureMultipartHandling(MultipartConfig(maxFileSize = Some(FileUtil.MaxFileSize)))
post("/image") { post("/image") {
setMultipartConfig()
execute( execute(
{ (file, fileId) => { (file, fileId) =>
FileUtils FileUtils
@@ -44,6 +45,7 @@ class FileUploadController
} }
post("/tmp") { post("/tmp") {
setMultipartConfig()
execute( execute(
{ (file, fileId) => { (file, fileId) =>
FileUtils FileUtils
@@ -55,6 +57,7 @@ class FileUploadController
} }
post("/file/:owner/:repository") { post("/file/:owner/:repository") {
setMultipartConfig()
execute( execute(
{ (file, fileId) => { (file, fileId) =>
FileUtils.writeByteArrayToFile( FileUtils.writeByteArrayToFile(
@@ -70,6 +73,7 @@ class FileUploadController
} }
post("/wiki/:owner/:repository") { post("/wiki/:owner/:repository") {
setMultipartConfig()
// Don't accept not logged-in users // Don't accept not logged-in users
session.get(Keys.Session.LoginAccount).collect { session.get(Keys.Session.LoginAccount).collect {
case loginAccount: Account => case loginAccount: Account =>
@@ -128,6 +132,7 @@ class FileUploadController
} }
post("/release/:owner/:repository/:tag") { post("/release/:owner/:repository/:tag") {
setMultipartConfigForLargeFile()
session session
.get(Keys.Session.LoginAccount) .get(Keys.Session.LoginAccount)
.collect { .collect {
@@ -150,6 +155,7 @@ class FileUploadController
post("/import") { post("/import") {
import JDBCUtil._ import JDBCUtil._
setMultipartConfig()
session.get(Keys.Session.LoginAccount).collect { session.get(Keys.Session.LoginAccount).collect {
case loginAccount: Account if loginAccount.isAdmin => case loginAccount: Account if loginAccount.isAdmin =>
execute({ (file, fileId) => execute({ (file, fileId) =>
@@ -159,6 +165,18 @@ class FileUploadController
redirect("/admin/data") 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 = { private def onlyWikiEditable(owner: String, repository: String, loginAccount: Account)(action: => Any): Any = {
implicit val session = Database.getSession(request) implicit val session = Database.getSession(request)
getRepository(owner, repository) match { getRepository(owner, repository) match {

View File

@@ -94,7 +94,13 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
"webhook" -> mapping( "webhook" -> mapping(
"blockPrivateAddress" -> trim(label("Block private address", boolean())), "blockPrivateAddress" -> trim(label("Block private address", boolean())),
"whitelist" -> trim(label("Whitelist", multiLineText())) "whitelist" -> trim(label("Whitelist", multiLineText()))
)(WebHook.apply) )(WebHook.apply),
"upload" -> mapping(
"maxFileSize" -> trim(label("Max file size", long(required))),
"timeout" -> trim(label("Timeout", long(required))),
"largeMaxFileSize" -> trim(label("Max file size for large file", long(required))),
"largeTimeout" -> trim(label("Timeout for large file", long(required)))
)(Upload.apply)
)(SystemSettings.apply).verifying { settings => )(SystemSettings.apply).verifying { settings =>
Vector( Vector(
if (settings.ssh.enabled && settings.baseUrl.isEmpty) { if (settings.ssh.enabled && settings.baseUrl.isEmpty) {

View File

@@ -72,6 +72,10 @@ trait SystemSettingsService {
props.setProperty(ShowMailAddress, settings.showMailAddress.toString) props.setProperty(ShowMailAddress, settings.showMailAddress.toString)
props.setProperty(WebHookBlockPrivateAddress, settings.webHook.blockPrivateAddress.toString) props.setProperty(WebHookBlockPrivateAddress, settings.webHook.blockPrivateAddress.toString)
props.setProperty(WebHookWhitelist, settings.webHook.whitelist.mkString("\n")) props.setProperty(WebHookWhitelist, settings.webHook.whitelist.mkString("\n"))
props.setProperty(UploadMaxFileSize, settings.upload.maxFileSize.toString)
props.setProperty(UploadTimeout, settings.upload.timeout.toString)
props.setProperty(UploadLargeMaxFileSize, settings.upload.largeMaxFileSize.toString)
props.setProperty(UploadLargeTimeout, settings.upload.largeTimeout.toString)
Using.resource(new java.io.FileOutputStream(GitBucketConf)) { out => Using.resource(new java.io.FileOutputStream(GitBucketConf)) { out =>
props.store(out, null) props.store(out, null)
@@ -149,7 +153,13 @@ trait SystemSettingsService {
}, },
getValue(props, SkinName, "skin-blue"), getValue(props, SkinName, "skin-blue"),
getValue(props, ShowMailAddress, false), getValue(props, ShowMailAddress, false),
WebHook(getValue(props, WebHookBlockPrivateAddress, false), getSeqValue(props, WebHookWhitelist, "")) WebHook(getValue(props, WebHookBlockPrivateAddress, false), getSeqValue(props, WebHookWhitelist, "")),
Upload(
getValue(props, UploadMaxFileSize, 3 * 1024 * 1024),
getValue(props, UploadTimeout, 3 * 10000),
getValue(props, UploadLargeMaxFileSize, 3 * 1024 * 1024),
getValue(props, UploadLargeTimeout, 3 * 10000)
)
) )
} }
} }
@@ -179,7 +189,8 @@ object SystemSettingsService {
oidc: Option[OIDC], oidc: Option[OIDC],
skinName: String, skinName: String,
showMailAddress: Boolean, showMailAddress: Boolean,
webHook: WebHook webHook: WebHook,
upload: Upload
) { ) {
def baseUrl(request: HttpServletRequest): String = def baseUrl(request: HttpServletRequest): String =
@@ -258,6 +269,8 @@ object SystemSettingsService {
case class WebHook(blockPrivateAddress: Boolean, whitelist: Seq[String]) case class WebHook(blockPrivateAddress: Boolean, whitelist: Seq[String])
case class Upload(maxFileSize: Long, timeout: Long, largeMaxFileSize: Long, largeTimeout: Long)
val DefaultSshPort = 29418 val DefaultSshPort = 29418
val DefaultSmtpPort = 25 val DefaultSmtpPort = 25
val DefaultLdapPort = 389 val DefaultLdapPort = 389
@@ -302,13 +315,12 @@ object SystemSettingsService {
private val OidcJwsAlgorithm = "oidc.jws_algorithm" private val OidcJwsAlgorithm = "oidc.jws_algorithm"
private val SkinName = "skinName" private val SkinName = "skinName"
private val ShowMailAddress = "showMailAddress" private val ShowMailAddress = "showMailAddress"
private val PluginNetworkInstall = "plugin.networkInstall"
private val PluginProxyHost = "plugin.proxy.host"
private val PluginProxyPort = "plugin.proxy.port"
private val PluginProxyUser = "plugin.proxy.user"
private val PluginProxyPassword = "plugin.proxy.password"
private val WebHookBlockPrivateAddress = "webhook.block_private_address" private val WebHookBlockPrivateAddress = "webhook.block_private_address"
private val WebHookWhitelist = "webhook.whitelist" private val WebHookWhitelist = "webhook.whitelist"
private val UploadMaxFileSize = "upload.maxFileSize"
private val UploadTimeout = "upload.timeout"
private val UploadLargeMaxFileSize = "upload.largeMaxFileSize"
private val UploadLargeTimeout = "upload.largeTimeout"
private def getValue[A: ClassTag](props: java.util.Properties, key: String, default: A): A = { private def getValue[A: ClassTag](props: java.util.Properties, key: String, default: A): A = {
getConfigValue(key).getOrElse { getConfigValue(key).getOrElse {

View File

@@ -92,12 +92,4 @@ object FileUtil {
name name
} }
lazy val MaxFileSize: Long = {
ConfigUtil.getConfigValue[Long]("gitbucket.maxFileSize").getOrElse(3 * 1024 * 1024)
}
lazy val UploadTimeout: Long = {
ConfigUtil.getConfigValue[Long]("gitbucket.UploadTimeout").getOrElse(3 * 10000)
}
} }

View File

@@ -7,12 +7,16 @@
<form action="@context.path/admin/system" method="POST" validate="true" class="form-horizontal" autocomplete="off"> <form action="@context.path/admin/system" method="POST" validate="true" class="form-horizontal" autocomplete="off">
<ul class="nav nav-tabs fill-width" id="pullreq-tab"> <ul class="nav nav-tabs fill-width" id="pullreq-tab">
<li><a href="#system">System settings</a></li> <li><a href="#system">System settings</a></li>
<li><a href="#integrations">Integrations</a></li>
<li><a href="#authentication">Authentication</a></li> <li><a href="#authentication">Authentication</a></li>
</ul> </ul>
<div class="tab-content fill-width" style="padding-top: 20px;"> <div class="tab-content fill-width" style="padding-top: 20px;">
<div class="tab-pane" id="system"> <div class="tab-pane" id="system">
@settings_system(info) @settings_system(info)
</div> </div>
<div class="tab-pane" id="integrations">
@settings_integrations(info)
</div>
<div class="tab-pane" id="authentication"> <div class="tab-pane" id="authentication">
@settings_authentication(info) @settings_authentication(info)
</div> </div>
@@ -30,6 +34,9 @@ $(function(){
if(location.hash == '#authentication'){ if(location.hash == '#authentication'){
$('li:has(a[href="#authentication"])').addClass('active'); $('li:has(a[href="#authentication"])').addClass('active');
$('div#authentication').addClass('active'); $('div#authentication').addClass('active');
} else if(location.hash == '#integrations'){
$('li:has(a[href="#integrations"])').addClass('active');
$('div#integrations').addClass('active');
} else { } else {
$('li:has(a[href="#system"])').addClass('active'); $('li:has(a[href="#system"])').addClass('active');
$('div#system').addClass('active'); $('div#system').addClass('active');

View File

@@ -0,0 +1,196 @@
@(info: Option[Any])(implicit context: gitbucket.core.controller.Context)
@import gitbucket.core.util.DatabaseConfig
<!--====================================================================-->
<!-- Services -->
<!--====================================================================-->
<label class="strong">Services</label>
<fieldset>
<label class="checkbox">
<input type="checkbox" name="gravatar"@if(context.settings.gravatar){ checked}/>
Use Gravatar for profile images
</label>
</fieldset>
<!--====================================================================-->
<!-- SSH access -->
<!--====================================================================-->
<hr>
<label class="strong">SSH access</label>
<fieldset>
<label class="checkbox">
<input type="checkbox" id="sshEnabled" name="ssh.enabled"@if(context.settings.ssh.enabled){ checked}/>
Enable SSH access to git repository
<span class="muted normal">(Both SSH host and Base URL are required if SSH access is enabled)</span>
</label>
</fieldset>
<div class="ssh">
<div class="form-group">
<label class="control-label col-md-2" for="sshHost">SSH host</label>
<div class="col-md-10">
<input type="text" id="sshHost" name="ssh.host" class="form-control" value="@context.settings.ssh.sshHost"/>
<span id="error-ssh_host" class="error"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="sshPort">SSH port</label>
<div class="col-md-10">
<input type="text" id="sshPort" name="ssh.port" class="form-control" value="@context.settings.ssh.sshPort"/>
<span id="error-ssh_port" class="error"></span>
</div>
</div>
</div>
<!--====================================================================-->
<!-- Communication email -->
<!--====================================================================-->
<hr>
<label class="strong">Communication</label>
<fieldset>
<label class="checkbox">
<input type="checkbox" id="useSMTP" name="useSMTP" @if(context.settings.useSMTP){ checked}/>
SMTP
<span class="muted normal">(Enable notification as well as SMTP configuration if you want to send notification email too)</span>
</label>
</fieldset>
<div class="useSMTP">
<div class="form-group">
<label class="control-label col-md-2" for="smtpHost">SMTP host</label>
<div class="col-md-10">
<input type="text" id="smtpHost" name="smtp.host" class="form-control" value="@context.settings.smtp.map(_.host)"/>
<span id="error-smtp_host" class="error"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="smtpPort">SMTP port</label>
<div class="col-md-10">
<input type="text" id="smtpPort" name="smtp.port" class="form-control input-mini" value="@context.settings.smtp.map(_.port)"/>
<span id="error-smtp_port" class="error"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="smtpUser">SMTP user</label>
<div class="col-md-10">
<input type="text" id="smtpUser" name="smtp.user" class="form-control" value="@context.settings.smtp.map(_.user)"/>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="smtpPassword">SMTP password</label>
<div class="col-md-10">
<input type="password" id="smtpPassword" name="smtp.password" class="form-control" value="@context.settings.smtp.map(_.password)"/>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="smtpSsl">Enable SSL</label>
<div class="col-md-10">
<input type="checkbox" id="smtpSsl" name="smtp.ssl"@if(context.settings.smtp.flatMap(_.ssl).getOrElse(false)){ checked}/>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="smtpStarttls">Enable STARTTLS</label>
<div class="col-md-10">
<input type="checkbox" id="smtpStarttls" name="smtp.starttls"@if(context.settings.smtp.flatMap(_.starttls).getOrElse(false)){ checked}/>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="fromAddress">FROM address</label>
<div class="col-md-10">
<input type="text" id="fromAddress" name="smtp.fromAddress" class="form-control" value="@context.settings.smtp.map(_.fromAddress)"/>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="fromName">FROM name</label>
<div class="col-md-10">
<input type="text" id="fromName" name="smtp.fromName" class="form-control" value="@context.settings.smtp.map(_.fromName)"/>
</div>
</div>
<div class="text-right">
Send test mail to:
<input type="text" id="testAddress" size="30"/>
<input type="button" id="sendTestMail" value="Send"/>
</div>
</div>
<!--====================================================================-->
<!-- Notification email -->
<!--====================================================================-->
<hr>
<label class="strong">Notifications</label>
<fieldset>
<label class="checkbox" for="notification">
<input type="checkbox" id="notification" name="notification"@if(context.settings.notification){ checked}/>
Send notifications
</label>
</fieldset>
<!--====================================================================-->
<!-- Web hook -->
<!--====================================================================-->
<hr>
<label class="strong">Web hook</label>
<fieldset>
<label class="checkbox" for="blockPrivateAddress">
<input type="checkbox" id="blockPrivateAddress" name="webhook.blockPrivateAddress"@if(context.settings.webHook.blockPrivateAddress){ checked}/>
Block sending to private addresses
</label>
</fieldset>
<div class="webhook">
<label><span class="strong">IP whitelist</span></label>
<fieldset>
<textarea name="webhook.whitelist" class="form-control" style="height: 100px;">@context.settings.webHook.whitelist.mkString("\n")</textarea>
</fieldset>
</div>
<script>
$(function(){
$('#sendTestMail').click(function(){
var host = $('#smtpHost' ).val();
var port = $('#smtpPort' ).val();
var user = $('#smtpUser' ).val();
var password = $('#smtpPassword').val();
var ssl = $('#smtpSsl' ).prop('checked');
var starttls = $('#smtpStarttls').prop('checked');
var fromAddress = $('#fromAddress' ).val();
var fromName = $('#fromName' ).val();
var testAddress = $('#testAddress' ).val();
if(host == ''){
alert('SMTP Host is required.');
$('#smtpHost').focus();
} else if(testAddress == ''){
alert('Destination is required.');
$('#testAddress').focus();
} else {
$.post('@context.path/admin/system/sendmail', {
'smtp.host': host,
'smtp.port': port,
'smtp.user': user,
'smtp.password': password,
'smtp.ssl': ssl,
'smtp.starttls': starttls,
'smtp.fromAddress': fromAddress,
'smtp.fromName': fromName,
'testAddress': testAddress
}, function(data, status){
if(data != ''){
alert(data);
}
});
}
});
$('#sshEnabled').change(function(){
$('.ssh input').prop('disabled', !$(this).prop('checked'));
}).change();
$('#useSMTP').change(function(){
$('.useSMTP input').prop('disabled', !$(this).prop('checked'));
// With only SMTP in current version, notification cannot be enabled if no communication channel exists
$('#notification').prop('disabled', !$(this).prop('checked'));
if (!$(this).prop('checked')) {
// With only SMTP in current version, if SMTP is unchecked then we disable notification
$('#notification').prop('checked', false);
}
}).change();
$('#blockPrivateAddress').change(function(){
$('.webhook textarea').prop('disabled', !$(this).prop('checked'));
}).change();
});
</script>

View File

@@ -151,6 +151,41 @@
</label> </label>
</fieldset> </fieldset>
<!--====================================================================--> <!--====================================================================-->
<!-- File upload -->
<!--====================================================================-->
<hr>
<label class="strong">File upload</label>
<fieldset>
<div class="form-group">
<label class="control-label col-md-2" for="uploadMaxFileSize">Max size</label>
<div class="col-md-10">
<input type="text" id="uploadMaxFileSize" name="upload.maxFileSize" class="form-control input-mini" value="@context.settings.upload.maxFileSize"/>
<span id="error-upload_maxFileSize" class="error"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="uploadTimeout">Timeout</label>
<div class="col-md-10">
<input type="text" id="uploadTimeout" name="upload.timeout" class="form-control input-mini" value="@context.settings.upload.timeout"/>
<span id="error-upload_timeout" class="error"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="uploadLargeMaxFileSize">Max size for large files</label>
<div class="col-md-10">
<input type="text" id="uploadLargeMaxFileSize" name="upload.largeMaxFileSize" class="form-control input-mini" value="@context.settings.upload.largeMaxFileSize"/>
<span id="error-upload_largeMaxFileSize" class="error"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="uploadLargeTimeout">Timeout for large files</label>
<div class="col-md-10">
<input type="text" id="uploadLargeTimeout" name="upload.largeTimeout" class="form-control input-mini" value="@context.settings.upload.largeTimeout"/>
<span id="error-upload_largeTimeout" class="error"></span>
</div>
</div>
</fieldset>
<!--====================================================================-->
<!-- Activity --> <!-- Activity -->
<!--====================================================================--> <!--====================================================================-->
<hr> <hr>
@@ -164,142 +199,6 @@
</div> </div>
</div> </div>
</fieldset> </fieldset>
<!--====================================================================-->
<!-- Services -->
<!--====================================================================-->
<hr>
<label class="strong">Services</label>
<fieldset>
<label class="checkbox">
<input type="checkbox" name="gravatar"@if(context.settings.gravatar){ checked}/>
Use Gravatar for profile images
</label>
</fieldset>
<!--====================================================================-->
<!-- SSH access -->
<!--====================================================================-->
<hr>
<label class="strong">SSH access</label>
<fieldset>
<label class="checkbox">
<input type="checkbox" id="sshEnabled" name="ssh.enabled"@if(context.settings.ssh.enabled){ checked}/>
Enable SSH access to git repository
<span class="muted normal">(Both SSH host and Base URL are required if SSH access is enabled)</span>
</label>
</fieldset>
<div class="ssh">
<div class="form-group">
<label class="control-label col-md-2" for="sshHost">SSH host</label>
<div class="col-md-10">
<input type="text" id="sshHost" name="ssh.host" class="form-control" value="@context.settings.ssh.sshHost"/>
<span id="error-ssh_host" class="error"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="sshPort">SSH port</label>
<div class="col-md-10">
<input type="text" id="sshPort" name="ssh.port" class="form-control" value="@context.settings.ssh.sshPort"/>
<span id="error-ssh_port" class="error"></span>
</div>
</div>
</div>
<!--====================================================================-->
<!-- Communication email -->
<!--====================================================================-->
<hr>
<label class="strong">Communication</label>
<fieldset>
<label class="checkbox">
<input type="checkbox" id="useSMTP" name="useSMTP" @if(context.settings.useSMTP){ checked}/>
SMTP
<span class="muted normal">(Enable notification as well as SMTP configuration if you want to send notification email too)</span>
</label>
</fieldset>
<div class="useSMTP">
<div class="form-group">
<label class="control-label col-md-2" for="smtpHost">SMTP host</label>
<div class="col-md-10">
<input type="text" id="smtpHost" name="smtp.host" class="form-control" value="@context.settings.smtp.map(_.host)"/>
<span id="error-smtp_host" class="error"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="smtpPort">SMTP port</label>
<div class="col-md-10">
<input type="text" id="smtpPort" name="smtp.port" class="form-control input-mini" value="@context.settings.smtp.map(_.port)"/>
<span id="error-smtp_port" class="error"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="smtpUser">SMTP user</label>
<div class="col-md-10">
<input type="text" id="smtpUser" name="smtp.user" class="form-control" value="@context.settings.smtp.map(_.user)"/>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="smtpPassword">SMTP password</label>
<div class="col-md-10">
<input type="password" id="smtpPassword" name="smtp.password" class="form-control" value="@context.settings.smtp.map(_.password)"/>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="smtpSsl">Enable SSL</label>
<div class="col-md-10">
<input type="checkbox" id="smtpSsl" name="smtp.ssl"@if(context.settings.smtp.flatMap(_.ssl).getOrElse(false)){ checked}/>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="smtpStarttls">Enable STARTTLS</label>
<div class="col-md-10">
<input type="checkbox" id="smtpStarttls" name="smtp.starttls"@if(context.settings.smtp.flatMap(_.starttls).getOrElse(false)){ checked}/>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="fromAddress">FROM address</label>
<div class="col-md-10">
<input type="text" id="fromAddress" name="smtp.fromAddress" class="form-control" value="@context.settings.smtp.map(_.fromAddress)"/>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="fromName">FROM name</label>
<div class="col-md-10">
<input type="text" id="fromName" name="smtp.fromName" class="form-control" value="@context.settings.smtp.map(_.fromName)"/>
</div>
</div>
<div class="text-right">
Send test mail to:
<input type="text" id="testAddress" size="30"/>
<input type="button" id="sendTestMail" value="Send"/>
</div>
</div>
<!--====================================================================-->
<!-- Notification email -->
<!--====================================================================-->
<hr>
<label class="strong">Notifications</label>
<fieldset>
<label class="checkbox" for="notification">
<input type="checkbox" id="notification" name="notification"@if(context.settings.notification){ checked}/>
Send notifications
</label>
</fieldset>
<!--====================================================================-->
<!-- Web hook -->
<!--====================================================================-->
<hr>
<label class="strong">Web hook</label>
<fieldset>
<label class="checkbox" for="blockPrivateAddress">
<input type="checkbox" id="blockPrivateAddress" name="webhook.blockPrivateAddress"@if(context.settings.webHook.blockPrivateAddress){ checked}/>
Block sending to private addresses
</label>
</fieldset>
<div class="webhook">
<label><span class="strong">IP whitelist</span></label>
<fieldset>
<textarea name="webhook.whitelist" class="form-control" style="height: 100px;">@context.settings.webHook.whitelist.mkString("\n")</textarea>
</fieldset>
</div>
<script> <script>
$(function(){ $(function(){
$('#skinName').change(function(evt) { $('#skinName').change(function(evt) {
@@ -309,61 +208,5 @@ $(function(){
themeCss.attr('href', themeCss.attr('href').replace(oldVal, that.val())); themeCss.attr('href', themeCss.attr('href').replace(oldVal, that.val()));
$(document.body).removeClass(oldVal).addClass(that.val()); $(document.body).removeClass(oldVal).addClass(that.val());
}); });
$('#sendTestMail').click(function(){
var host = $('#smtpHost' ).val();
var port = $('#smtpPort' ).val();
var user = $('#smtpUser' ).val();
var password = $('#smtpPassword').val();
var ssl = $('#smtpSsl' ).prop('checked');
var starttls = $('#smtpStarttls').prop('checked');
var fromAddress = $('#fromAddress' ).val();
var fromName = $('#fromName' ).val();
var testAddress = $('#testAddress' ).val();
if(host == ''){
alert('SMTP Host is required.');
$('#smtpHost').focus();
} else if(testAddress == ''){
alert('Destination is required.');
$('#testAddress').focus();
} else {
$.post('@context.path/admin/system/sendmail', {
'smtp.host': host,
'smtp.port': port,
'smtp.user': user,
'smtp.password': password,
'smtp.ssl': ssl,
'smtp.starttls': starttls,
'smtp.fromAddress': fromAddress,
'smtp.fromName': fromName,
'testAddress': testAddress
}, function(data, status){
if(data != ''){
alert(data);
}
});
}
});
$('#sshEnabled').change(function(){
$('.ssh input').prop('disabled', !$(this).prop('checked'));
}).change();
$('#useSMTP').change(function(){
$('.useSMTP input').prop('disabled', !$(this).prop('checked'));
// With only SMTP in current version, notification cannot be enabled if no communication channel exists
$('#notification').prop('disabled', !$(this).prop('checked'));
if (!$(this).prop('checked')) {
// With only SMTP in current version, if SMTP is unchecked then we disable notification
$('#notification').prop('checked', false);
}
}).change();
$('#blockPrivateAddress').change(function(){
$('.webhook textarea').prop('disabled', !$(this).prop('checked'));
}).change();
}); });
</script> </script>

View File

@@ -65,9 +65,8 @@ $(function(){
} }
@dropzone(clickable: Boolean, textareaId: Option[String]) = { @dropzone(clickable: Boolean, textareaId: Option[String]) = {
url: '@context.path/upload/file/@repository.owner/@repository.name', url: '@context.path/upload/file/@repository.owner/@repository.name',
maxFilesize: @{FileUtil.MaxFileSize / 1024 / 1024}, maxFilesize: @{context.settings.upload.maxFileSize / 1024 / 1024},
//timeout defaults to 30 secs timeout: @{context.settings.upload.timeout},
timeout: @{FileUtil.UploadTimeout},
clickable: @clickable, clickable: @clickable,
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>", previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
success: function(file, id) { success: function(file, id) {

View File

@@ -71,10 +71,9 @@ $(function(){
}); });
$("#drop").dropzone({ $("#drop").dropzone({
maxFilesize: @{gitbucket.core.util.FileUtil.MaxFileSize / 1024 / 1024},
url: '@context.path/upload/release/@repository.owner/@repository.name/@helpers.encodeRefName(tag.name)', url: '@context.path/upload/release/@repository.owner/@repository.name/@helpers.encodeRefName(tag.name)',
//timeout defaults to 30 secs maxFilesize: @{context.settings.upload.largeMaxFileSize / 1024 / 1024},
timeout: @{gitbucket.core.util.FileUtil.UploadTimeout}, timeout: @{context.settings.upload.largeTimeout},
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>", previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
success: function(file, id) { success: function(file, id) {
var attach = var attach =

View File

@@ -51,7 +51,8 @@
$(function(){ $(function(){
$('#upload-area').dropzone({ $('#upload-area').dropzone({
url: '@context.path/upload/tmp', url: '@context.path/upload/tmp',
maxFilesize: @{FileUtil.MaxFileSize / 1024 / 1024}, maxFilesize: @{context.settings.upload.maxFileSize / 1024 / 1024},
timeout: @{context.settings.upload.timeout},
clickable: true, clickable: true,
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>", previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
success: function(file, id) { success: function(file, id) {

View File

@@ -48,7 +48,8 @@ $(function(){
try { try {
$('#content1').dropzone({ $('#content1').dropzone({
url: '@context.path/upload/wiki/@repository.owner/@repository.name', url: '@context.path/upload/wiki/@repository.owner/@repository.name',
maxFilesize: @{FileUtil.MaxFileSize / 1024 / 1024}, maxFilesize: @{context.settings.upload.maxFileSize / 1024 / 1024},
timeout: @{context.settings.upload.timeout},
clickable: false, clickable: false,
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>", previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
success: function(file, id) { success: function(file, id) {
@@ -59,7 +60,8 @@ $(function(){
}); });
$('.clickable').dropzone({ $('.clickable').dropzone({
url: '@context.path/upload/wiki/@repository.owner/@repository.name', url: '@context.path/upload/wiki/@repository.owner/@repository.name',
maxFilesize: @{FileUtil.MaxFileSize / 1024 / 1024}, maxFilesize: @{context.settings.upload.maxFileSize / 1024 / 1024},
timeout: @{context.settings.upload.timeout},
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>", previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
success: function(file, id) { success: function(file, id) {
var attachFile = (file.type.match(/image\/.*/) ? '\n![' + file.name.split('.')[0] : '\n[' + file.name) + '](' + file.name + ')'; var attachFile = (file.type.match(/image\/.*/) ? '\n![' + file.name.split('.')[0] : '\n[' + file.name) + '](' + file.name + ')';

View File

@@ -55,6 +55,12 @@ trait ServiceSpecBase extends MockitoSugar {
webHook = SystemSettingsService.WebHook( webHook = SystemSettingsService.WebHook(
blockPrivateAddress = false, blockPrivateAddress = false,
whitelist = Nil whitelist = Nil
),
upload = SystemSettingsService.Upload(
maxFileSize = 3 * 1024 * 1024,
timeout = 30 * 10000,
largeMaxFileSize = 3 * 1024 * 1024,
largeTimeout = 30 * 10000
) )
) )

View File

@@ -7,7 +7,7 @@ import javax.servlet.http.{HttpServletRequest, HttpSession}
import gitbucket.core.controller.Context import gitbucket.core.controller.Context
import gitbucket.core.model.Account import gitbucket.core.model.Account
import gitbucket.core.service.RequestCache import gitbucket.core.service.RequestCache
import gitbucket.core.service.SystemSettingsService.{Ssh, SystemSettings, WebHook} import gitbucket.core.service.SystemSettingsService.{Ssh, SystemSettings, WebHook, Upload}
import org.mockito.Mockito._ import org.mockito.Mockito._
import org.scalatest.FunSpec import org.scalatest.FunSpec
import org.scalatestplus.mockito.MockitoSugar import org.scalatestplus.mockito.MockitoSugar
@@ -141,6 +141,12 @@ class AvatarImageProviderSpec extends FunSpec with MockitoSugar {
webHook = WebHook( webHook = WebHook(
blockPrivateAddress = false, blockPrivateAddress = false,
whitelist = Nil whitelist = Nil
),
upload = Upload(
maxFileSize = 3 * 1024 * 1024,
timeout = 30 * 10000,
largeMaxFileSize = 3 * 1024 * 1024,
largeTimeout = 30 * 10000
) )
) )