mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-22 23:50:32 +00:00
d6fa853a37
added the "initprovider" command to initialize the database structure. If we change the database schema the required changes will be checked at startup and automatically applyed.
354 lines
No EOL
16 KiB
HTML
354 lines
No EOL
16 KiB
HTML
{{template "base" .}}
|
|
|
|
{{define "title"}}{{.Title}}{{end}}
|
|
|
|
{{define "extra_css"}}
|
|
<link href="/static/vendor/tempusdominus/css/tempusdominus-bootstrap-4.min.css" rel="stylesheet">
|
|
{{end}}
|
|
|
|
{{define "page_body"}}
|
|
|
|
<!-- Page Heading -->
|
|
<h1 class="h5 mb-4 text-gray-800">{{if .IsAdd}}Add a new user{{else}}Edit user{{end}}</h1>
|
|
{{if .Error}}
|
|
<div class="card mb-4 border-left-warning">
|
|
<div class="card-body text-form-error">{{.Error}}</div>
|
|
</div>
|
|
{{end}}
|
|
<form id="user_form" enctype="multipart/form-data" action="{{.CurrentURL}}" method="POST" autocomplete="off">
|
|
<div class="form-group row">
|
|
<label for="idUsername" class="col-sm-2 col-form-label">Username</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idUsername" name="username" placeholder=""
|
|
value="{{.User.Username}}" maxlength="255" autocomplete="nope" required
|
|
{{if not .IsAdd}}readonly{{end}}>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idStatus" class="col-sm-2 col-form-label">Status</label>
|
|
<div class="col-sm-10">
|
|
<select class="form-control" id="idStatus" name="status">
|
|
<option value="1" {{if eq .User.Status 1 }}selected{{end}}>Active</option>
|
|
<option value="0" {{if eq .User.Status 0 }}selected{{end}}>Inactive</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idExpirationDate" class="col-sm-2 col-form-label">Expiration Date</label>
|
|
<div class="col-sm-10 input-group date" id="expirationDatePicker" data-target-input="nearest">
|
|
<input type="text" class="form-control datetimepicker-input" id="idExpirationDate"
|
|
data-target="#expirationDatePicker">
|
|
<div class="input-group-append" data-target="#expirationDatePicker" data-toggle="datetimepicker">
|
|
<div class="input-group-text"><i class="fas fa-calendar"></i></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idPassword" class="col-sm-2 col-form-label">Password</label>
|
|
<div class="col-sm-10">
|
|
<input type="password" class="form-control" id="idPassword" name="password" placeholder="" maxlength="255"
|
|
autocomplete="new-password" {{if not .IsAdd}}aria-describedby="pwdHelpBlock" {{end}}>
|
|
{{if not .IsAdd}}
|
|
<small id="pwdHelpBlock" class="form-text text-muted">
|
|
If empty the current password will not be changed
|
|
</small>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idPublicKeys" class="col-sm-2 col-form-label">Public keys</label>
|
|
<div class="col-sm-10">
|
|
<textarea class="form-control" id="idPublicKeys" name="public_keys" rows="3"
|
|
aria-describedby="pkHelpBlock">{{range .User.PublicKeys}}{{.}} {{end}}</textarea>
|
|
<small id="pkHelpBlock" class="form-text text-muted">
|
|
One public key per line
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idPermissions" class="col-sm-2 col-form-label">Permissions</label>
|
|
<div class="col-sm-10">
|
|
<select class="form-control" id="idPermissions" name="permissions" required multiple>
|
|
{{range $validPerm := .ValidPerms}}
|
|
<option value="{{$validPerm}}"
|
|
{{range $perm := $.RootDirPerms }}{{if eq $perm $validPerm}}selected{{end}}{{end}}>{{$validPerm}}
|
|
</option>
|
|
{{end}}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idSubDirsPermissions" class="col-sm-2 col-form-label">Sub dirs permissions</label>
|
|
<div class="col-sm-10">
|
|
<textarea class="form-control" id="idSubDirsPermissions" name="sub_dirs_permissions" rows="3"
|
|
aria-describedby="subDirsHelpBlock">{{range $dir, $perms := .User.Permissions -}}
|
|
{{if ne $dir "/" -}}
|
|
{{$dir}}:{{range $index, $p := $perms}}{{if $index}},{{end}}{{$p}}{{end}}
|
|
{{- end}}
|
|
{{- end}}</textarea>
|
|
<small id="subDirsHelpBlock" class="form-text text-muted">
|
|
One directory per line as dir:perms, for example /somedir:list,download
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idHomeDir" class="col-sm-2 col-form-label">Home Dir</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idHomeDir" name="home_dir" placeholder=""
|
|
value="{{.User.HomeDir}}" maxlength="255">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idQuotaFiles" class="col-sm-2 col-form-label">Quota files</label>
|
|
<div class="col-sm-3">
|
|
<input type="number" class="form-control" id="idQuotaFiles" name="quota_files" placeholder=""
|
|
value="{{.User.QuotaFiles}}" min="0" aria-describedby="qfHelpBlock">
|
|
<small id="qfHelpBlock" class="form-text text-muted">
|
|
0 means no limit
|
|
</small>
|
|
</div>
|
|
<div class="col-sm-2"></div>
|
|
<label for="idQuotaSize" class="col-sm-2 col-form-label">Quota size (bytes)</label>
|
|
<div class="col-sm-3">
|
|
<input type="number" class="form-control" id="idQuotaSize" name="quota_size" placeholder=""
|
|
value="{{.User.QuotaSize}}" min="0" aria-describedby="qsHelpBlock">
|
|
<small id="qsHelpBlock" class="form-text text-muted">
|
|
0 means no limit
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idUploadBandwidth" class="col-sm-2 col-form-label">Bandwidth UL (KB/s)</label>
|
|
<div class="col-sm-3">
|
|
<input type="number" class="form-control" id="idUploadBandwidth" name="upload_bandwidth" placeholder=""
|
|
value="{{.User.UploadBandwidth}}" min="0" aria-describedby="ulHelpBlock">
|
|
<small id="ulHelpBlock" class="form-text text-muted">
|
|
0 means no limit
|
|
</small>
|
|
</div>
|
|
<div class="col-sm-2"></div>
|
|
<label for="idDownloadBandwidth" class="col-sm-2 col-form-label">Bandwidth DL (KB/s)</label>
|
|
<div class="col-sm-3">
|
|
<input type="number" class="form-control" id="idDownloadBandwidth" name="download_bandwidth" placeholder=""
|
|
value="{{.User.DownloadBandwidth}}" min="0" aria-describedby="dlHelpBlock">
|
|
<small id="dlHelpBlock" class="form-text text-muted">
|
|
0 means no limit
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idMaxSessions" class="col-sm-2 col-form-label">Max sessions</label>
|
|
<div class="col-sm-2">
|
|
<input type="number" class="form-control" id="idMaxSessions" name="max_sessions" placeholder=""
|
|
value="{{.User.MaxSessions}}" min="0" aria-describedby="sessionsHelpBlock">
|
|
<small id="sessionsHelpBlock" class="form-text text-muted">
|
|
0 means no limit
|
|
</small>
|
|
</div>
|
|
<div class="col-sm-1"></div>
|
|
<label for="idUID" class="col-sm-1 col-form-label">UID</label>
|
|
<div class="col-sm-2">
|
|
<input type="number" class="form-control" id="idUID" name="uid" placeholder="" value="{{.User.UID}}" min="0"
|
|
max="65535">
|
|
</div>
|
|
<div class="col-sm-1"></div>
|
|
<label for="idGID" class="col-sm-1 col-form-label">GID</label>
|
|
<div class="col-sm-2">
|
|
<input type="number" class="form-control" id="idGID" name="gid" placeholder="" value="{{.User.GID}}" min="0"
|
|
max="65535">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idDeniedIP" class="col-sm-2 col-form-label">Denied IP/Mask</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idDeniedIP" name="denied_ip" placeholder=""
|
|
value="{{.User.GetDeniedIPAsString}}" maxlength="255" aria-describedby="deniedIPHelpBlock">
|
|
<small id="deniedIPHelpBlock" class="form-text text-muted">
|
|
Comma separated IP/Mask in CIDR format, for example "192.168.1.0/24,10.8.0.100/32"
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idAllowedIP" class="col-sm-2 col-form-label">Allowed IP/Mask</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idAllowedIP" name="allowed_ip" placeholder=""
|
|
value="{{.User.GetAllowedIPAsString}}" maxlength="255" aria-describedby="allowedIPHelpBlock">
|
|
<small id="allowedIPHelpBlock" class="form-text text-muted">
|
|
Comma separated IP/Mask in CIDR format, for example "192.168.1.0/24,10.8.0.100/32"
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idFilesystem" class="col-sm-2 col-form-label">Storage</label>
|
|
<div class="col-sm-10">
|
|
<select class="form-control" id="idFilesystem" name="fs_provider" onchange="onFilesystemChanged(this.value)">
|
|
<option value="0" {{if eq .User.FsConfig.Provider 0 }}selected{{end}}>local</option>
|
|
<option value="1" {{if eq .User.FsConfig.Provider 1 }}selected{{end}}>Amazon S3 (Compatible)</option>
|
|
<option value="2" {{if eq .User.FsConfig.Provider 2 }}selected{{end}}>Google Cloud Storage</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row s3">
|
|
<label for="idS3Bucket" class="col-sm-2 col-form-label">S3 Bucket</label>
|
|
<div class="col-sm-3">
|
|
<input type="text" class="form-control" id="idS3Bucket" name="s3_bucket" placeholder=""
|
|
value="{{.User.FsConfig.S3Config.Bucket}}" maxlength="255">
|
|
</div>
|
|
<div class="col-sm-2"></div>
|
|
<label for="idS3Region" class="col-sm-2 col-form-label">S3 Region</label>
|
|
<div class="col-sm-3">
|
|
<input type="text" class="form-control" id="idS3Region" name="s3_region" placeholder=""
|
|
value="{{.User.FsConfig.S3Config.Region}}" maxlength="255">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row s3">
|
|
<label for="idS3AccessKey" class="col-sm-2 col-form-label">S3 Access Key</label>
|
|
<div class="col-sm-3">
|
|
<input type="text" class="form-control" id="idS3AccessKey" name="s3_access_key" placeholder=""
|
|
value="{{.User.FsConfig.S3Config.AccessKey}}" maxlength="255">
|
|
</div>
|
|
<div class="col-sm-2"></div>
|
|
<label for="idS3AccessSecret" class="col-sm-2 col-form-label">S3 Access Secret</label>
|
|
<div class="col-sm-3">
|
|
<input type="text" class="form-control" id="idS3AccessSecret" name="s3_access_secret" placeholder=""
|
|
value="{{.User.FsConfig.S3Config.AccessSecret}}" maxlength="1000">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row s3">
|
|
<label for="idS3StorageClass" class="col-sm-2 col-form-label">S3 Storage Class</label>
|
|
<div class="col-sm-3">
|
|
<input type="text" class="form-control" id="idS3StorageClass" name="s3_storage_class" placeholder=""
|
|
value="{{.User.FsConfig.S3Config.StorageClass}}" maxlength="1000">
|
|
</div>
|
|
<div class="col-sm-2"></div>
|
|
<label for="idS3Endpoint" class="col-sm-2 col-form-label">S3 Endpoint</label>
|
|
<div class="col-sm-3">
|
|
<input type="text" class="form-control" id="idS3Endpoint" name="s3_endpoint" placeholder=""
|
|
value="{{.User.FsConfig.S3Config.Endpoint}}" maxlength="255">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row s3">
|
|
<label for="idS3KeyPrefix" class="col-sm-2 col-form-label">S3 Key Prefix</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idS3KeyPrefix" name="s3_key_prefix" placeholder=""
|
|
value="{{.User.FsConfig.S3Config.KeyPrefix}}" maxlength="255" aria-describedby="S3KeyPrefixHelpBlock">
|
|
<small id="S3KeyPrefixHelpBlock" class="form-text text-muted">
|
|
Similar to a chroot for local filesystem. Cannot start with "/". Example: "somedir/subdir/".
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row gcs">
|
|
<label for="idGCSBucket" class="col-sm-2 col-form-label">GCS Bucket</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idGCSBucket" name="gcs_bucket" placeholder=""
|
|
value="{{.User.FsConfig.GCSConfig.Bucket}}" maxlength="255">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row gcs">
|
|
<label for="idGCSCredentialFile" class="col-sm-2 col-form-label">GCS Credentials file</label>
|
|
<div class="col-sm-4">
|
|
<input type="file" class="form-control-file" id="idGCSCredentialFile" name="gcs_credential_file"
|
|
aria-describedby="GCSCredentialsHelpBlock">
|
|
<small id="GCSCredentialsHelpBlock" class="form-text text-muted">
|
|
Add or update credentials from a JSON file
|
|
</small>
|
|
</div>
|
|
<div class="col-sm-1"></div>
|
|
<label for="idGCSStorageClass" class="col-sm-2 col-form-label">GCS Storage Class</label>
|
|
<div class="col-sm-3">
|
|
<input type="text" class="form-control" id="idGCSStorageClass" name="gcs_storage_class" placeholder=""
|
|
value="{{.User.FsConfig.GCSConfig.StorageClass}}" maxlength="255">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row gcs">
|
|
<label for="idGCSKeyPrefix" class="col-sm-2 col-form-label">GCS Key Prefix</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idGCSKeyPrefix" name="gcs_key_prefix" placeholder=""
|
|
value="{{.User.FsConfig.GCSConfig.KeyPrefix}}" maxlength="255" aria-describedby="GCSKeyPrefixHelpBlock">
|
|
<small id="GCSKeyPrefixHelpBlock" class="form-text text-muted">
|
|
Similar to a chroot for local filesystem. Cannot start with "/". Example: "somedir/subdir/".
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<input type="hidden" name="expiration_date" id="hidden_start_datetime" value="">
|
|
<button type="submit" class="btn btn-primary float-right mt-3 mb-5 px-5 px-3">Submit</button>
|
|
</form>
|
|
{{end}}
|
|
|
|
{{define "extra_js"}}
|
|
<script src="/static/vendor/moment/js/moment.min.js"></script>
|
|
<script src="/static/vendor/tempusdominus/js/tempusdominus-bootstrap-4.min.js"></script>
|
|
<script type="text/javascript">
|
|
$(document).ready(function () {
|
|
|
|
$('#expirationDatePicker').datetimepicker({
|
|
format: 'YYYY-MM-DD',
|
|
buttons: {
|
|
showClear: false,
|
|
showClose: true,
|
|
showToday: false
|
|
}
|
|
});
|
|
|
|
{{ if gt .User.ExpirationDate 0 }}
|
|
var input_dt = moment({{.User.ExpirationDate }}).format('YYYY-MM-DD');
|
|
$('#idExpirationDate').val(input_dt);
|
|
$('#expirationDatePicker').datetimepicker('viewDate', input_dt);
|
|
{{ end }}
|
|
|
|
$("#user_form").submit(function (event) {
|
|
var dt = $('#idExpirationDate').val();
|
|
if (dt) {
|
|
var d = $('#expirationDatePicker').datetimepicker('viewDate');
|
|
if (d) {
|
|
var dateString = moment(d).format('YYYY-MM-DD HH:mm:ss');
|
|
$('#hidden_start_datetime').val(dateString);
|
|
} else {
|
|
$('#hidden_start_datetime').val("");
|
|
}
|
|
} else {
|
|
$('#hidden_start_datetime').val("");
|
|
}
|
|
return true;
|
|
});
|
|
|
|
onFilesystemChanged('{{.User.FsConfig.Provider}}');
|
|
|
|
});
|
|
|
|
function onFilesystemChanged(val){
|
|
if (val == '1'){
|
|
$('.form-group.row.gcs').hide();
|
|
$('.form-group.row.s3').show();
|
|
} else if (val == '2'){
|
|
$('.form-group.row.gcs').show();
|
|
$('.form-group.row.s3').hide();
|
|
} else {
|
|
$('.form-group.row.gcs').hide();
|
|
$('.form-group.row.s3').hide();
|
|
}
|
|
}
|
|
</script>
|
|
{{end}} |