mirror of
https://github.com/drakkan/sftpgo.git
synced 2025-12-09 08:15:13 +03:00
add groups support
Using groups simplifies the administration of multiple accounts by letting you assign settings once to a group, instead of multiple times to each individual user. Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
@@ -93,6 +93,14 @@
|
||||
</li>
|
||||
{{end}}
|
||||
|
||||
{{ if .LoggedAdmin.HasPermission "manage_groups"}}
|
||||
<li class="nav-item {{if eq .CurrentURL .GroupsURL}}active{{end}}">
|
||||
<a class="nav-link" href="{{.GroupsURL}}">
|
||||
<i class="fas fa-user-friends"></i>
|
||||
<span>{{.GroupsTitle}}</span></a>
|
||||
</li>
|
||||
{{end}}
|
||||
|
||||
{{ if .LoggedAdmin.HasPermission "view_conns"}}
|
||||
<li class="nav-item {{if eq .CurrentURL .ConnectionsURL}}active{{end}}">
|
||||
<a class="nav-link" href="{{.ConnectionsURL}}">
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
{{define "title"}}{{.Title}}{{end}}
|
||||
|
||||
{{define "extra_css"}}
|
||||
<link href="{{.StaticURL}}/vendor/bootstrap-select/css/bootstrap-select.min.css" rel="stylesheet">
|
||||
{{end}}
|
||||
|
||||
{{define "page_body"}}
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
@@ -92,6 +96,7 @@
|
||||
{{end}}
|
||||
|
||||
{{define "extra_js"}}
|
||||
<script src="{{.StaticURL}}/vendor/bootstrap-select/js/bootstrap-select.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
onFilesystemChanged('{{.Folder.FsConfig.Provider.Name}}');
|
||||
@@ -120,7 +125,7 @@
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
{{template "fsjs"}}
|
||||
</script>
|
||||
|
||||
{{template "fsjs"}}
|
||||
{{end}}
|
||||
@@ -7,7 +7,7 @@
|
||||
<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"
|
||||
<select class="form-control selectpicker" id="idFilesystem" name="fs_provider"
|
||||
onchange="onFilesystemChanged(this.value)">
|
||||
{{ range ListFSProviders }}
|
||||
<option value="{{.Name}}" {{if eq . $.Provider }}selected{{end}}>{{.ShortInfo}}</option>
|
||||
@@ -15,14 +15,14 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{{if .IsUserPage}}
|
||||
{{if or .IsUserPage .IsGroupPage}}
|
||||
<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="Absolute path to a local directory"
|
||||
value="{{.DirPath}}" aria-describedby="homeDirHelpBlock">
|
||||
<small id="homeDirHelpBlock" class="form-text text-muted">
|
||||
{{if not .DirPath}}{{if .HasUsersBaseDir}}Leave blank for an appropriate default{{else}}Required for local storage providers. For non-local filesystems it will store temporary files, you can leave blank for an appropriate default{{end}}{{end}}
|
||||
{{if not .DirPath}}{{if .HasUsersBaseDir}}Leave blank for an appropriate default{{else}}{{if .IsGroupPage}}Leave blank and the storage to "local" to not override the root filesystem{{else}}Required for local storage providers. For non-local filesystems it will store temporary files, you can leave blank for an appropriate default{{end}}{{end}}{{end}}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -299,7 +299,7 @@
|
||||
<div class="form-group row fsconfig fsconfig-azblobfs">
|
||||
<label for="idAzAccessTier" class="col-sm-2 col-form-label">Access Tier</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control" id="idAzAccessTier" name="az_access_tier">
|
||||
<select class="form-control selectpicker" id="idAzAccessTier" name="az_access_tier">
|
||||
<option value="" {{if eq .AzBlobConfig.AccessTier "" }}selected{{end}}>Default</option>
|
||||
<option value="Hot" {{if eq .AzBlobConfig.AccessTier "Hot" }}selected{{end}}>Hot</option>
|
||||
<option value="Cool" {{if eq .AzBlobConfig.AccessTier "Cool" }}selected{{end}}>Cool</option>
|
||||
@@ -459,6 +459,7 @@
|
||||
{{end}}
|
||||
|
||||
{{define "fsjs"}}
|
||||
<script type="text/javascript">
|
||||
function onFilesystemChanged(val){
|
||||
// each fsconfig form-group has the 'fsconfig' css class
|
||||
// as well as a 'fsconfig-{name}' class where name is the FilesystemProvider.Name
|
||||
@@ -466,4 +467,5 @@
|
||||
$('.form-group.fsconfig').hide();
|
||||
$('.form-group.fsconfig-'+val).show();
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
||||
754
templates/webadmin/group.html
Normal file
754
templates/webadmin/group.html
Normal file
@@ -0,0 +1,754 @@
|
||||
{{template "base" .}}
|
||||
|
||||
{{define "title"}}{{.Title}}{{end}}
|
||||
|
||||
{{define "extra_css"}}
|
||||
<link href="{{.StaticURL}}/vendor/bootstrap-select/css/bootstrap-select.min.css" rel="stylesheet">
|
||||
{{end}}
|
||||
|
||||
{{define "page_body"}}
|
||||
<!-- Page Heading -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">{{.Title}}</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{if .Error}}
|
||||
<div class="card mb-4 border-left-warning">
|
||||
<div class="card-body text-form-error">{{.Error}}</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="card mb-4 border-left-info">
|
||||
<div class="card-body">
|
||||
The <span class="text-success">%username%</span> placeholder will be replaced with the username of the associated users.
|
||||
</div>
|
||||
</div>
|
||||
<form id="group_form" enctype="multipart/form-data" action="{{.CurrentURL}}" method="POST" autocomplete="off">
|
||||
<div class="form-group row">
|
||||
<label for="idGroupName" class="col-sm-2 col-form-label">Name</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" id="idGroupName" name="name" placeholder=""
|
||||
value="{{.Group.Name}}" maxlength="255" autocomplete="nope" required {{if eq .Mode 2}}readonly{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="idDescription" class="col-sm-2 col-form-label">Description</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" id="idDescription" name="description" placeholder=""
|
||||
value="{{.Group.Description}}" maxlength="255" aria-describedby="descriptionHelpBlock">
|
||||
<small id="descriptionHelpBlock" class="form-text text-muted">
|
||||
Optional description
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "fshtml" .FsWrapper}}
|
||||
{{if .VirtualFolders}}
|
||||
<div class="card bg-light mb-3">
|
||||
<div class="card-header">
|
||||
<b>Virtual folders</b>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h6 class="card-title mb-4">Quota -1 means included within user quota, 0 unlimited. Don't set -1 for shared folders</h6>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-12 form_field_vfolders_outer">
|
||||
{{range $idx, $val := .Group.VirtualFolders}}
|
||||
<div class="row form_field_vfolder_outer_row">
|
||||
<div class="form-group col-md-3">
|
||||
<input type="text" class="form-control" id="idVolderPath{{$idx}}" name="vfolder_path" placeholder="mount path, i.e. /vfolder" value="{{$val.VirtualPath}}" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<select class="form-control selectpicker" data-live-search="true" id="idVfolderName{{$idx}}" name="vfolder_name">
|
||||
<option value=""></option>
|
||||
{{range $.VirtualFolders}}
|
||||
<option value="{{.Name}}" {{if eq $val.Name .Name}}selected{{end}}>{{.Name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<input type="number" class="form-control" id="idVfolderQuotaSize{{$idx}}" name="vfolder_quota_size"
|
||||
value="{{$val.QuotaSize}}" min="-1" aria-describedby="vqsHelpBlock{{$idx}}">
|
||||
<small id="vqsHelpBlock{{$idx}}" class="form-text text-muted">
|
||||
Quota size (bytes)
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group col-md-2">
|
||||
<input type="number" class="form-control" id="idVfolderQuotaFiles{{$idx}}" name="vfolder_quota_files"
|
||||
value="{{$val.QuotaFiles}}" min="-1" aria-describedby="vqfHelpBlock{{$idx}}">
|
||||
<small id="vqfHelpBlock{{$idx}}" class="form-text text-muted">
|
||||
Quota files
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_vfolder_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="row form_field_vfolder_outer_row">
|
||||
<div class="form-group col-md-3">
|
||||
<input type="text" class="form-control" id="idVolderPath0" name="vfolder_path" placeholder="mount path, i.e. /vfolder" value="" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<select class="form-control selectpicker" data-live-search="true" id="idVfolderName0" name="vfolder_name">
|
||||
<option value=""></option>
|
||||
{{range .VirtualFolders}}
|
||||
<option value="{{.Name}}">{{.Name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<input type="number" class="form-control" id="idVfolderQuotaSize0" name="vfolder_quota_size"
|
||||
value="" min="-1" aria-describedby="vqsHelpBlock0">
|
||||
<small id="vqsHelpBlock0" class="form-text text-muted">
|
||||
Quota size (bytes)
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group col-md-2">
|
||||
<input type="number" class="form-control" id="idVfolderQuotaFiles0" name="vfolder_quota_files"
|
||||
value="" min="-1" aria-describedby="vqfHelpBlock0">
|
||||
<small id="vqfHelpBlock0" class="form-text text-muted">
|
||||
Quota files
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_vfolder_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mx-1">
|
||||
<button type="button" class="btn btn-secondary add_new_vfolder_field_btn">
|
||||
<i class="fas fa-plus"></i> Add new virtual folder
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="accordion" id="accordionUser">
|
||||
<div class="card">
|
||||
<div class="card-header" id="headingPermissions">
|
||||
<h2 class="mb-0">
|
||||
<button class="btn btn-link btn-block text-left" type="button" data-toggle="collapse"
|
||||
data-target="#collapsePermissions" aria-expanded="true" aria-controls="collapsePermissions">
|
||||
<h6 class="m-0 font-weight-bold text-primary">ACLs</h6>
|
||||
</button>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div id="collapsePermissions" class="collapse" aria-labelledby="headingPermissions" data-parent="#accordionUser">
|
||||
<div class="card-body">
|
||||
<div class="card bg-light mb-3">
|
||||
<div class="card-header">
|
||||
<b>Per-directory permissions</b>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group row">
|
||||
<div class="col-md-12 form_field_dirperms_outer">
|
||||
{{range $idx, $dirPerms := .Group.GetPermissions -}}
|
||||
<div class="row form_field_dirperms_outer_row">
|
||||
<div class="form-group col-md-8">
|
||||
<input type="text" class="form-control" id="idSubDirPermsPath{{$idx}}" name="sub_perm_path{{$idx}}" placeholder="directory path, i.e. /dir" value="{{$dirPerms.Path}}" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<select class="form-control selectpicker" id="idSubDirPermissions{{$idx}}" name="sub_perm_permissions{{$idx}}" multiple>
|
||||
{{range $validPerm := $.ValidPerms}}
|
||||
<option value="{{$validPerm}}" {{range $perm := $dirPerms.Permissions }}{{if eq $perm $validPerm}}selected{{end}}{{end}}>{{$validPerm}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_dirperms_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="row form_field_dirperms_outer_row">
|
||||
<div class="form-group col-md-8">
|
||||
<input type="text" class="form-control" id="idSubDirPermsPath0" name="sub_perm_path0" placeholder="directory path, i.e. /dir" value="" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<select class="form-control selectpicker" id="idSubDirPermissions0" name="sub_perm_permissions0" multiple>
|
||||
{{range $validPerm := .ValidPerms}}
|
||||
<option value="{{$validPerm}}">{{$validPerm}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_dirperms_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mx-1">
|
||||
<button type="button" class="btn btn-secondary add_new_dirperms_field_btn">
|
||||
<i class="fas fa-plus"></i> Add new directory permissions
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mb-3">
|
||||
<div class="card-header">
|
||||
<b>Per-directory pattern restrictions</b>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h6 class="card-title mb-4">Comma separated denied or allowed files/directories, based on shell patterns.</h6>
|
||||
<p class="card-text">Denied entries are visible in directory listing by default, you can hide them by setting the "Hidden" policy, but please be aware that this may cause performance issues for large directories</p>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-12 form_field_patterns_outer">
|
||||
{{range $idx, $pattern := .Group.UserSettings.Filters.GetFlatFilePatterns -}}
|
||||
<div class="row form_field_patterns_outer_row">
|
||||
<div class="form-group col-md-3">
|
||||
<input type="text" class="form-control" id="idPatternPath{{$idx}}" name="pattern_path{{$idx}}" placeholder="directory path, i.e. /dir" value="{{$pattern.Path}}" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
<input type="text" class="form-control" id="idPatterns{{$idx}}" name="patterns{{$idx}}" placeholder="*.zip,?.txt" value="{{$pattern.GetCommaSeparatedPatterns}}" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-2">
|
||||
<select class="form-control selectpicker" id="idPatternType{{$idx}}" name="pattern_type{{$idx}}">
|
||||
<option value="denied" {{if $pattern.IsDenied}}selected{{end}}>Denied</option>
|
||||
<option value="allowed" {{if $pattern.IsAllowed}}selected{{end}}>Allowed</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-2">
|
||||
<select class="form-control selectpicker" id="idPatternPolicy{{$idx}}" name="pattern_policy{{$idx}}">
|
||||
<option value="0" {{if eq $pattern.DenyPolicy 0}}selected{{end}}>Visible</option>
|
||||
<option value="1" {{if eq $pattern.DenyPolicy 1}}selected{{end}}>Hidden</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_pattern_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="row form_field_patterns_outer_row">
|
||||
<div class="form-group col-md-3">
|
||||
<input type="text" class="form-control" id="idPatternPath0" name="pattern_path0" placeholder="directory path, i.e. /dir" value="" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
<input type="text" class="form-control" id="idPatterns0" name="patterns0" placeholder="*.zip,?.txt" value="" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-2">
|
||||
<select class="form-control selectpicker" id="idPatternType0" name="pattern_type0">
|
||||
<option value="denied">Denied</option>
|
||||
<option value="allowed">Allowed</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-2">
|
||||
<select class="form-control selectpicker" id="idPatternPolicy0" name="pattern_policy0">
|
||||
<option value="0">Visible</option>
|
||||
<option value="1">Hidden</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_pattern_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mx-1">
|
||||
<button type="button" class="btn btn-secondary add_new_pattern_field_btn">
|
||||
<i class="fas fa-plus"></i> Add new file pattern
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="idMaxSessions" class="col-sm-2 col-form-label">Max sessions</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" id="idMaxSessions" name="max_sessions" placeholder=""
|
||||
value="{{.Group.UserSettings.MaxSessions}}" min="0" aria-describedby="sessionsHelpBlock">
|
||||
<small id="sessionsHelpBlock" class="form-text text-muted">
|
||||
Maximun number of concurrent sessions. 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="idProtocols" class="col-sm-2 col-form-label">Denied protocols</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control selectpicker" id="idProtocols" name="denied_protocols" multiple>
|
||||
{{range $protocol := .ValidProtocols}}
|
||||
<option value="{{$protocol}}" {{range $p :=$.Group.UserSettings.Filters.DeniedProtocols }}{{if eq $p $protocol}}selected{{end}}{{end}}>{{$protocol}}
|
||||
</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="idLoginMethods" class="col-sm-2 col-form-label">Denied login methods</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control selectpicker" id="idLoginMethods" name="denied_login_methods" multiple aria-describedby="deniedLoginMethodsHelpBlock">
|
||||
{{range $method := .ValidLoginMethods}}
|
||||
<option value="{{$method}}" {{range $m :=$.Group.UserSettings.Filters.DeniedLoginMethods }}{{if eq $m $method}}selected{{end}}{{end}}>{{$method}}
|
||||
</option>
|
||||
{{end}}
|
||||
</select>
|
||||
<small id="deniedLoginMethodsHelpBlock" class="form-text text-muted">
|
||||
"password" is valid for all supported protocols, "password-over-SSH" only for SSH/SFTP/SCP
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="idTwoFactorProtocols" class="col-sm-2 col-form-label">Require two-factor auth for</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control selectpicker" id="idTwoFactorProtocols" name="required_two_factor_protocols" multiple>
|
||||
{{range $protocol := .TwoFactorProtocols}}
|
||||
<option value="{{$protocol}}" {{range $p :=$.Group.UserSettings.Filters.TwoFactorAuthProtocols }}{{if eq $p $protocol}}selected{{end}}{{end}}>{{$protocol}}
|
||||
</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="idWebClient" class="col-sm-2 col-form-label">Web client/REST API</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control selectpicker" id="idWebClient" name="web_client_options" multiple>
|
||||
{{range $option := .WebClientOptions}}
|
||||
<option value="{{$option}}" {{range $p :=$.Group.UserSettings.Filters.WebClient }}{{if eq $p $option}}selected{{end}}{{end}}>{{$option}}
|
||||
</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</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">
|
||||
<textarea class="form-control" id="idDeniedIP" name="denied_ip" rows="3" placeholder=""
|
||||
aria-describedby="deniedIPHelpBlock">{{.Group.GetDeniedIPAsString}}</textarea>
|
||||
<small id="deniedIPHelpBlock" class="form-text text-muted">
|
||||
Comma separated IP/Mask in CIDR format, 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">
|
||||
<textarea class="form-control" id="idAllowedIP" name="allowed_ip" rows="3" placeholder=""
|
||||
aria-describedby="allowedIPHelpBlock">{{.Group.GetAllowedIPAsString}}</textarea>
|
||||
<small id="allowedIPHelpBlock" class="form-text text-muted">
|
||||
Comma separated IP/Mask in CIDR format, example: "192.168.1.0/24,10.8.0.100/32"
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header" id="headingQuota">
|
||||
<h2 class="mb-0">
|
||||
<button class="btn btn-link btn-block text-left collapsed" type="button" data-toggle="collapse"
|
||||
data-target="#collapseQuota" aria-expanded="false" aria-controls="collapseQuota">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Disk quota and bandwidth limits</h6>
|
||||
</button>
|
||||
</h2>
|
||||
</div>
|
||||
<div id="collapseQuota" class="collapse" aria-labelledby="headingTwo" data-parent="#accordionUser">
|
||||
<div class="card-body">
|
||||
|
||||
<div class="form-group row">
|
||||
<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="{{.Group.UserSettings.QuotaSize}}" min="0" aria-describedby="qsHelpBlock">
|
||||
<small id="qsHelpBlock" class="form-text text-muted">
|
||||
0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-sm-2"></div>
|
||||
<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="{{.Group.UserSettings.QuotaFiles}}" min="0" aria-describedby="qfHelpBlock">
|
||||
<small id="qfHelpBlock" class="form-text text-muted">
|
||||
0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="idMaxUploadSize" class="col-sm-2 col-form-label">Max file upload size (bytes)</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" id="idMaxUploadSize" name="max_upload_file_size"
|
||||
placeholder="" value="{{.Group.UserSettings.Filters.MaxUploadFileSize}}" min="0"
|
||||
aria-describedby="fqsHelpBlock">
|
||||
<small id="fqsHelpBlock" class="form-text text-muted">
|
||||
Maximum upload size for a single file. 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="{{.Group.UserSettings.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="{{.Group.UserSettings.DownloadBandwidth}}" min="0" aria-describedby="dlHelpBlock">
|
||||
<small id="dlHelpBlock" class="form-text text-muted">
|
||||
0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mb-3">
|
||||
<div class="card-header">
|
||||
<b>Per-source bandwidth speed limits</b>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group row">
|
||||
<div class="col-md-12 form_field_bwlimits_outer">
|
||||
{{range $idx, $bwLimit := .Group.UserSettings.Filters.BandwidthLimits -}}
|
||||
<div class="row form_field_bwlimits_outer_row">
|
||||
<div class="form-group col-md-8">
|
||||
<textarea class="form-control" id="idBandwidthLimitSources{{$idx}}" name="bandwidth_limit_sources{{$idx}}" rows="4" placeholder=""
|
||||
aria-describedby="bwLimitSourcesHelpBlock{{$idx}}">{{$bwLimit.GetSourcesAsString}}</textarea>
|
||||
<small id="bwLimitSourcesHelpBlock{{$idx}}" class="form-text text-muted">
|
||||
Comma separated IP/Mask in CIDR format, example: "192.168.1.0/24,10.8.0.100/32"
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idUploadBandwidthSource{{$idx}}" name="upload_bandwidth_source{{$idx}}"
|
||||
placeholder="" value="{{$bwLimit.UploadBandwidth}}" min="0" aria-describedby="ulHelpBlock{{$idx}}">
|
||||
<small id="ulHelpBlock{{$idx}}" class="form-text text-muted">
|
||||
UL (KB/s). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idDownloadBandwidthSource{{$idx}}" name="download_bandwidth_source{{$idx}}"
|
||||
placeholder="" value="{{$bwLimit.DownloadBandwidth}}" min="0" aria-describedby="dlHelpBlock{{$idx}}">
|
||||
<small id="dlHelpBlock{{$idx}}" class="form-text text-muted">
|
||||
DL (KB/s). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_bwlimit_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="row form_field_bwlimits_outer_row">
|
||||
<div class="form-group col-md-8">
|
||||
<textarea class="form-control" id="idBandwidthLimitSources0" name="bandwidth_limit_sources0" rows="4" placeholder=""
|
||||
aria-describedby="bwLimitSourcesHelpBlock0"></textarea>
|
||||
<small id="bwLimitSourcesHelpBlock0" class="form-text text-muted">
|
||||
Comma separated IP/Mask in CIDR format, example: "192.168.1.0/24,10.8.0.100/32"
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idUploadBandwidthSource0" name="upload_bandwidth_source0"
|
||||
placeholder="" value="" min="0" aria-describedby="ulHelpBlock0">
|
||||
<small id="ulHelpBlock0" class="form-text text-muted">
|
||||
UL (KB/s). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idDownloadBandwidthSource0" name="download_bandwidth_source0"
|
||||
placeholder="" value="" min="0" aria-describedby="dlHelpBlock0">
|
||||
<small id="dlHelpBlock0" class="form-text text-muted">
|
||||
DL (KB/s). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_bwlimit_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mx-1">
|
||||
<button type="button" class="btn btn-secondary add_new_bwlimit_field_btn">
|
||||
<i class="fas fa-plus"></i> Add new speed limit
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="idTransferUL" class="col-sm-2 col-form-label">Upload data transfer (MB)</label>
|
||||
<div class="col-sm-3">
|
||||
<input type="number" class="form-control" id="idTransferUL" name="upload_data_transfer" placeholder=""
|
||||
value="{{.Group.UserSettings.UploadDataTransfer}}" min="0" aria-describedby="ulTransferHelpBlock">
|
||||
<small id="ulTransferHelpBlock" class="form-text text-muted">
|
||||
Maximum data transfer allowed for uploads. 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-sm-2"></div>
|
||||
<label for="idTransferDL" class="col-sm-2 col-form-label">Download data transfer (MB)</label>
|
||||
<div class="col-sm-3">
|
||||
<input type="number" class="form-control" id="idTransferDL" name="download_data_transfer" placeholder=""
|
||||
value="{{.Group.UserSettings.DownloadDataTransfer}}" min="0" aria-describedby="dlTransferHelpBlock">
|
||||
<small id="dlTransferHelpBlock" class="form-text text-muted">
|
||||
Maximum data transfer allowed for downloads. 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="idTransferTotal" class="col-sm-2 col-form-label">Total data transfer (MB)</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" id="idTransferTotal" name="total_data_transfer"
|
||||
placeholder="" value="{{.Group.UserSettings.TotalDataTransfer}}" min="0"
|
||||
aria-describedby="totalTransferHelpBlock">
|
||||
<small id="totalTransferHelpBlock" class="form-text text-muted">
|
||||
Maximum data transfer allowed for uploads + downloads. Replace the individual limits. 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mb-3">
|
||||
<div class="card-header">
|
||||
<b>Per-source data transfer limits</b>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group row">
|
||||
<div class="col-md-12 form_field_dtlimits_outer">
|
||||
{{range $idx, $dtLimit := .Group.UserSettings.Filters.DataTransferLimits -}}
|
||||
<div class="row form_field_dtlimits_outer_row">
|
||||
<div class="form-group col-md-5">
|
||||
<textarea class="form-control" id="idDataTransferLimitSources{{$idx}}" name="data_transfer_limit_sources{{$idx}}" rows="4" placeholder=""
|
||||
aria-describedby="dtLimitSourcesHelpBlock{{$idx}}">{{$dtLimit.GetSourcesAsString}}</textarea>
|
||||
<small id="dtLimitSourcesHelpBlock{{$idx}}" class="form-text text-muted">
|
||||
Comma separated IP/Mask in CIDR format, example: "192.168.1.0/24,10.8.0.100/32"
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idUploadTransferSource{{$idx}}" name="upload_data_transfer_source{{$idx}}"
|
||||
placeholder="" value="{{$dtLimit.UploadDataTransfer}}" min="0" aria-describedby="ulDtHelpBlock{{$idx}}">
|
||||
<small id="ulDtHelpBlock{{$idx}}" class="form-text text-muted">
|
||||
UL (MB). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idDownloadTransferSource{{$idx}}" name="download_data_transfer_source{{$idx}}"
|
||||
placeholder="" value="{{$dtLimit.DownloadDataTransfer}}" min="0" aria-describedby="dlDtHelpBlock{{$idx}}">
|
||||
<small id="dlDtHelpBlock{{$idx}}" class="form-text text-muted">
|
||||
DL (MB). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idTotalTransferSource{{$idx}}" name="total_data_transfer_source{{$idx}}"
|
||||
placeholder="" value="{{$dtLimit.TotalDataTransfer}}" min="0" aria-describedby="totalDtHelpBlock{{$idx}}">
|
||||
<small id="totalDtHelpBlock{{$idx}}" class="form-text text-muted">
|
||||
Total (MB). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_dtlimit_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="row form_field_dtlimits_outer_row">
|
||||
<div class="form-group col-md-5">
|
||||
<textarea class="form-control" id="idDataTransferLimitSources0" name="data_transfer_limit_sources0" rows="4" placeholder=""
|
||||
aria-describedby="dtLimitSourcesHelpBlock0"></textarea>
|
||||
<small id="dtLimitSourcesHelpBlock0" class="form-text text-muted">
|
||||
Comma separated IP/Mask in CIDR format, example: "192.168.1.0/24,10.8.0.100/32"
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idUploadTransferSource0" name="upload_data_transfer_source0"
|
||||
placeholder="" value="" min="0" aria-describedby="ulDtHelpBlock0">
|
||||
<small id="ulDtHelpBlock0" class="form-text text-muted">
|
||||
UL (MB). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idDownloadTransferSource0" name="download_data_transfer_source0"
|
||||
placeholder="" value="" min="0" aria-describedby="dlDtHelpBlock0">
|
||||
<small id="dlDtHelpBlock0" class="form-text text-muted">
|
||||
DL (MB). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idTotalTransferSource0" name="total_data_transfer_source0"
|
||||
placeholder="" value="" min="0" aria-describedby="totalDtHelpBlock0">
|
||||
<small id="totalDtHelpBlock0" class="form-text text-muted">
|
||||
Total (MB). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_dtlimit_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mx-1">
|
||||
<button type="button" class="btn btn-secondary add_new_dtlimit_field_btn">
|
||||
<i class="fas fa-plus"></i> Add new data transfer limit
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header" id="headingAdvanced">
|
||||
<h2 class="mb-0">
|
||||
<button class="btn btn-link btn-block text-left collapsed" type="button" data-toggle="collapse"
|
||||
data-target="#collapseAdvanced" aria-expanded="false" aria-controls="collapseAdvanced">
|
||||
<h6 class="m-0 font-weight-bold text-primary">More</h6>
|
||||
</button>
|
||||
</h2>
|
||||
</div>
|
||||
<div id="collapseAdvanced" class="collapse" aria-labelledby="headingTwo" data-parent="#accordionUser">
|
||||
<div class="card-body">
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="idStartDirectory" class="col-sm-2 col-form-label">Start directory</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" id="idStartDirectory" name="start_directory" placeholder=""
|
||||
value="{{.Group.UserSettings.Filters.StartDirectory}}" aria-describedby="startDirHelpBlock">
|
||||
<small id="startDirHelpBlock" class="form-text text-muted">
|
||||
Alternate start directory to use instead of "/". Supported for SFTP/FTP/HTTP
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="idTLSUsername" class="col-sm-2 col-form-label">TLS username</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control selectpicker" id="idTLSUsername" name="tls_username" aria-describedby="tlsUsernameHelpBlock">
|
||||
<option value="None" {{if eq .Group.UserSettings.Filters.TLSUsername "None" }}selected{{end}}>None</option>
|
||||
<option value="CommonName" {{if eq .Group.UserSettings.Filters.TLSUsername "CommonName" }}selected{{end}}>Common Name</option>
|
||||
</select>
|
||||
<small id="tlsUsernameHelpBlock" class="form-text text-muted">
|
||||
Defines the TLS certificate field to use as username. Ignored if mutual TLS is disabled
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="idHooks" class="col-sm-2 col-form-label">Hooks</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control selectpicker" id="idHooks" name="hooks" multiple>
|
||||
<option value="external_auth_disabled" {{if .Group.UserSettings.Filters.Hooks.ExternalAuthDisabled}}selected{{end}}>
|
||||
External auth disabled
|
||||
</option>
|
||||
<option value="pre_login_disabled" {{if .Group.UserSettings.Filters.Hooks.PreLoginDisabled}}selected{{end}}>
|
||||
Pre-login disabled
|
||||
</option>
|
||||
<option value="check_password_disabled" {{if .Group.UserSettings.Filters.Hooks.CheckPasswordDisabled}}selected{{end}}>
|
||||
Check password disabled
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="idDisableFsChecks" name="disable_fs_checks"
|
||||
{{if .Group.UserSettings.Filters.DisableFsChecks}}checked{{end}} aria-describedby="disableFsChecksHelpBlock">
|
||||
<label for="idDisableFsChecks" class="form-check-label">Disable filesystem checks</label>
|
||||
<small id="disableFsChecksHelpBlock" class="form-text text-muted">
|
||||
Disable checks for existence and automatic creation of home directory and virtual folders
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="idAllowAPIKeyAuth" name="allow_api_key_auth"
|
||||
{{if .Group.UserSettings.Filters.AllowAPIKeyAuth}}checked{{end}} aria-describedby="allowAPIKeyAuthHelpBlock">
|
||||
<label for="idAllowAPIKeyAuth" class="form-check-label">Allow API key authentication</label>
|
||||
<small id="allowAPIKeyAuthHelpBlock" class="form-text text-muted">
|
||||
Allow to impersonate the associated users, in REST API, with an API key
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row {{if not .Group.HasExternalAuth}}d-none{{end}}">
|
||||
<label for="idExtAuthCacheTime" class="col-sm-2 col-form-label">External auth cache time</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" min="0" class="form-control" id="idExtAuthCacheTime" name="external_auth_cache_time" placeholder=""
|
||||
value="{{.Group.UserSettings.Filters.ExternalAuthCacheTime}}" aria-describedby="extAuthCacheHelpBlock">
|
||||
<small id="extAuthCacheHelpBlock" class="form-text text-muted">
|
||||
Cache time, in seconds, for users authenticated using an external auth hook. 0 means no cache
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="_form_token" value="{{.CSRFToken}}">
|
||||
<div class="col-sm-12 text-right px-0">
|
||||
<button type="submit" class="btn btn-primary mt-3 ml-3 px-5" name="form_action" value="submit">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{define "extra_js"}}
|
||||
<script src="{{.StaticURL}}/vendor/bootstrap-select/js/bootstrap-select.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
{{if .Error}}
|
||||
$('#accordionUser .collapse').removeAttr("data-parent").collapse('show');
|
||||
{{end}}
|
||||
onFilesystemChanged('{{.Group.UserSettings.FsConfig.Provider.Name}}');
|
||||
});
|
||||
</script>
|
||||
|
||||
{{template "fsjs"}}
|
||||
{{template "shared_user_group" .}}
|
||||
{{end}}
|
||||
193
templates/webadmin/groups.html
Normal file
193
templates/webadmin/groups.html
Normal file
@@ -0,0 +1,193 @@
|
||||
{{template "base" .}}
|
||||
|
||||
{{define "title"}}{{.Title}}{{end}}
|
||||
|
||||
{{define "extra_css"}}
|
||||
<link href="{{.StaticURL}}/vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/buttons.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/fixedHeader.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/responsive.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/select.bootstrap4.min.css" rel="stylesheet">
|
||||
{{end}}
|
||||
|
||||
{{define "page_body"}}
|
||||
<div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
|
||||
<div id="errorTxt" class="card-body text-form-error"></div>
|
||||
</div>
|
||||
|
||||
<div id="successMsg" class="card mb-4 border-left-success" style="display: none;">
|
||||
<div id="successTxt" class="card-body"></div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">View and manage groups</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover nowrap" id="dataTable" width="100%" cellspacing="0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Used by</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .Groups}}
|
||||
<tr>
|
||||
<td>{{.Name}}</td>
|
||||
<td>{{.Description}}</td>
|
||||
<td>{{.GetUsersAsString}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{define "dialog"}}
|
||||
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="deleteModalLabel"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="deleteModalLabel">
|
||||
Confirmation required
|
||||
</h5>
|
||||
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">Do you want to delete the selected group? A referenced group cannot be removed</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" type="button" data-dismiss="modal">
|
||||
Cancel
|
||||
</button>
|
||||
<a class="btn btn-warning" href="#" onclick="deleteAction()">
|
||||
Delete
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{define "extra_js"}}
|
||||
<script src="{{.StaticURL}}/vendor/datatables/jquery.dataTables.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.bootstrap4.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.buttons.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/buttons.bootstrap4.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.fixedHeader.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.responsive.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/responsive.bootstrap4.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.select.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
function deleteAction() {
|
||||
var table = $('#dataTable').DataTable();
|
||||
table.button('delete:name').enable(false);
|
||||
var groupName = table.row({ selected: true }).data()[0];
|
||||
var path = '{{.GroupURL}}' + "/" + fixedEncodeURIComponent(groupName);
|
||||
$('#deleteModal').modal('hide');
|
||||
$.ajax({
|
||||
url: path,
|
||||
type: 'DELETE',
|
||||
dataType: 'json',
|
||||
headers: {'X-CSRF-TOKEN' : '{{.CSRFToken}}'},
|
||||
timeout: 15000,
|
||||
success: function (result) {
|
||||
window.location.href = '{{.GroupsURL}}';
|
||||
},
|
||||
error: function ($xhr, textStatus, errorThrown) {
|
||||
var txt = "Unable to delete the selected group";
|
||||
if ($xhr) {
|
||||
var json = $xhr.responseJSON;
|
||||
if (json) {
|
||||
if (json.message){
|
||||
txt += ": " + json.message;
|
||||
} else {
|
||||
txt += ": " + json.error;
|
||||
}
|
||||
}
|
||||
}
|
||||
$('#errorTxt').text(txt);
|
||||
$('#errorMsg').show();
|
||||
setTimeout(function () {
|
||||
$('#errorMsg').hide();
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
$.fn.dataTable.ext.buttons.add = {
|
||||
text: '<i class="fas fa-plus"></i>',
|
||||
name: 'add',
|
||||
titleAttr: "Add",
|
||||
action: function (e, dt, node, config) {
|
||||
window.location.href = '{{.GroupURL}}';
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.dataTable.ext.buttons.edit = {
|
||||
text: '<i class="fas fa-pen"></i>',
|
||||
name: 'edit',
|
||||
titleAttr: "Edit",
|
||||
action: function (e, dt, node, config) {
|
||||
var groupName = table.row({ selected: true }).data()[0];
|
||||
var path = '{{.GroupURL}}' + "/" + fixedEncodeURIComponent(groupName);
|
||||
window.location.href = path;
|
||||
},
|
||||
enabled: false
|
||||
};
|
||||
|
||||
$.fn.dataTable.ext.buttons.delete = {
|
||||
text: '<i class="fas fa-trash"></i>',
|
||||
name: 'delete',
|
||||
titleAttr: "Delete",
|
||||
action: function (e, dt, node, config) {
|
||||
$('#deleteModal').modal('show');
|
||||
},
|
||||
enabled: false
|
||||
};
|
||||
|
||||
var table = $('#dataTable').DataTable({
|
||||
"select": {
|
||||
"style": "single",
|
||||
"blurable": true
|
||||
},
|
||||
"stateSave": true,
|
||||
"stateDuration": 0,
|
||||
"buttons": [],
|
||||
"scrollX": false,
|
||||
"scrollY": false,
|
||||
"responsive": true,
|
||||
"language": {
|
||||
"emptyTable": "No group defined"
|
||||
},
|
||||
"order": [[0, 'asc']]
|
||||
});
|
||||
|
||||
new $.fn.dataTable.FixedHeader( table );
|
||||
|
||||
{{if .LoggedAdmin.HasPermission "manage_groups"}}
|
||||
table.button().add(0,'delete');
|
||||
table.button().add(0,'edit');
|
||||
table.button().add(0,'add');
|
||||
|
||||
table.buttons().container().appendTo('.col-md-6:eq(0)', table.table().container());
|
||||
|
||||
table.on('select deselect', function () {
|
||||
var selectedRows = table.rows({ selected: true }).count();
|
||||
table.button('delete:name').enable(selectedRows == 1);
|
||||
table.button('edit:name').enable(selectedRows == 1);
|
||||
});
|
||||
{{end}}
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
{{end}}
|
||||
217
templates/webadmin/sharedcomponents.html
Normal file
217
templates/webadmin/sharedcomponents.html
Normal file
@@ -0,0 +1,217 @@
|
||||
{{define "shared_user_group"}}
|
||||
<script type="text/javascript">
|
||||
$("body").on("click", ".add_new_dirperms_field_btn", function () {
|
||||
var index = $(".form_field_dirperms_outer").find(".form_field_dirperms_outer_row").length;
|
||||
while (document.getElementById("idSubDirPermsPath"+index) != null){
|
||||
index++;
|
||||
}
|
||||
$(".form_field_dirperms_outer").append(`
|
||||
<div class="row form_field_dirperms_outer_row">
|
||||
<div class="form-group col-md-8">
|
||||
<input type="text" class="form-control" id="idSubDirPermsPath${index}" name="sub_perm_path${index}" placeholder="directory path, i.e. /dir" value="" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<select class="form-control" id="idSubDirPermissions${index}" name="sub_perm_permissions${index}" multiple>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_dirperms_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
{{- range .ValidPerms}}
|
||||
$("#idSubDirPermissions"+index).append($('<option>').val('{{.}}').text('{{.}}'));
|
||||
{{- end}}
|
||||
$("#idSubDirPermissions"+index).selectpicker();
|
||||
});
|
||||
|
||||
$("body").on("click", ".remove_dirperms_btn_frm_field", function () {
|
||||
$(this).closest(".form_field_dirperms_outer_row").remove();
|
||||
});
|
||||
|
||||
$("body").on("click", ".add_new_vfolder_field_btn", function () {
|
||||
var index = $(".form_field_vfolders_outer").find(".form_field_vfolder_outer_row").length;
|
||||
while (document.getElementById("idVolderPath" + index) != null) {
|
||||
index++;
|
||||
}
|
||||
$(".form_field_vfolders_outer").append(`
|
||||
<div class="row form_field_vfolder_outer_row">
|
||||
<div class="form-group col-md-3">
|
||||
<input type="text" class="form-control" id="idVolderPath${index}" name="vfolder_path" placeholder="mount path, i.e. /vfolder" value="" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<select class="form-control" id="idVfolderName${index}" name="vfolder_name">
|
||||
<option value=""></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<input type="number" class="form-control" id="idVfolderQuotaSize${index}" name="vfolder_quota_size"
|
||||
value="" min="-1" aria-describedby="vqsHelpBlock${index}">
|
||||
<small id="vqsHelpBlock${index}" class="form-text text-muted">
|
||||
Quota size (bytes)
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group col-md-2">
|
||||
<input type="number" class="form-control" id="idVfolderQuotaFiles${index}" name="vfolder_quota_files"
|
||||
value="" min="-1" aria-describedby="vqfHelpBlock${index}">
|
||||
<small id="vqfHelpBlock${index}" class="form-text text-muted">
|
||||
Quota files
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_vfolder_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
{{- range .VirtualFolders}}
|
||||
$("#idVfolderName"+index).append($('<option>').val('{{.Name}}').text('{{.Name}}'));
|
||||
{{- end}}
|
||||
$("#idVfolderName"+index).selectpicker({'liveSearch': true});
|
||||
});
|
||||
|
||||
$("body").on("click", ".remove_vfolder_btn_frm_field", function () {
|
||||
$(this).closest(".form_field_vfolder_outer_row").remove();
|
||||
});
|
||||
|
||||
$("body").on("click", ".add_new_bwlimit_field_btn", function () {
|
||||
var index = $(".form_field_bwlimits_outer").find(".form_field_bwlimits_outer_row").length;
|
||||
while (document.getElementById("idBandwidthLimitSources"+index) != null){
|
||||
index++;
|
||||
}
|
||||
$(".form_field_bwlimits_outer").append(`
|
||||
<div class="row form_field_bwlimits_outer_row">
|
||||
<div class="form-group col-md-8">
|
||||
<textarea class="form-control" id="idBandwidthLimitSources0" name="bandwidth_limit_sources${index}" rows="4" placeholder=""
|
||||
aria-describedby="bwLimitSourcesHelpBlock${index}"></textarea>
|
||||
<small id="bwLimitSourcesHelpBlock${index}" class="form-text text-muted">
|
||||
Comma separated IP/Mask in CIDR format, example: "192.168.1.0/24,10.8.0.100/32"
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idUploadBandwidthSource${index}" name="upload_bandwidth_source${index}"
|
||||
placeholder="" value="" min="0" aria-describedby="ulHelpBlock${index}">
|
||||
<small id="ulHelpBlock${index}" class="form-text text-muted">
|
||||
UL (KB/s). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idDownloadBandwidthSource${index}" name="download_bandwidth_source${index}"
|
||||
placeholder="" value="" min="0" aria-describedby="dlHelpBlock${index}">
|
||||
<small id="dlHelpBlock${index}" class="form-text text-muted">
|
||||
DL (KB/s). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_bwlimit_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
|
||||
$("body").on("click", ".remove_bwlimit_btn_frm_field", function () {
|
||||
$(this).closest(".form_field_bwlimits_outer_row").remove();
|
||||
});
|
||||
|
||||
$("body").on("click", ".add_new_dtlimit_field_btn", function () {
|
||||
var index = $(".form_field_dtlimits_outer").find(".form_field_dtlimits_outer_row").length;
|
||||
while (document.getElementById("idDataTransferLimitSources"+index) != null){
|
||||
index++;
|
||||
}
|
||||
$(".form_field_dtlimits_outer").append(`
|
||||
<div class="row form_field_dtlimits_outer_row">
|
||||
<div class="form-group col-md-5">
|
||||
<textarea class="form-control" id="idDataTransferLimitSources${index}" name="data_transfer_limit_sources${index}" rows="4" placeholder=""
|
||||
aria-describedby="dtLimitSourcesHelpBlock${index}"></textarea>
|
||||
<small id="dtLimitSourcesHelpBlock${index}" class="form-text text-muted">
|
||||
Comma separated IP/Mask in CIDR format, example: "192.168.1.0/24,10.8.0.100/32"
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idUploadTransferSource${index}" name="upload_data_transfer_source${index}"
|
||||
placeholder="" value="" min="0" aria-describedby="ulDtHelpBlock${index}">
|
||||
<small id="ulDtHelpBlock${index}" class="form-text text-muted">
|
||||
UL (MB). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idDownloadTransferSource${index}" name="download_data_transfer_source${index}"
|
||||
placeholder="" value="" min="0" aria-describedby="dlDtHelpBlock${index}">
|
||||
<small id="dlDtHelpBlock${index}" class="form-text text-muted">
|
||||
DL (MB). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idTotalTransferSource${index}" name="total_data_transfer_source${index}"
|
||||
placeholder="" value="" min="0" aria-describedby="totalDtHelpBlock${index}">
|
||||
<small id="totalDtHelpBlock${index}" class="form-text text-muted">
|
||||
Total (MB). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_dtlimit_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
|
||||
$("body").on("click", ".remove_dtlimit_btn_frm_field", function () {
|
||||
$(this).closest(".form_field_dtlimits_outer_row").remove();
|
||||
});
|
||||
|
||||
$("body").on("click", ".add_new_pattern_field_btn", function () {
|
||||
var index = $(".form_field_patterns_outer").find(".form_field_patterns_outer_row").length;
|
||||
while (document.getElementById("idPatternPath"+index) != null){
|
||||
index++;
|
||||
}
|
||||
$(".form_field_patterns_outer").append(`
|
||||
<div class="row form_field_patterns_outer_row">
|
||||
<div class="form-group col-md-3">
|
||||
<input type="text" class="form-control" id="idPatternPath${index}" name="pattern_path${index}" placeholder="directory path, i.e. /dir" value="" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
<input type="text" class="form-control" id="idPatterns${index}" name="patterns${index}" placeholder="*.zip,?.txt" value="" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-2">
|
||||
<select class="form-control" id="idPatternType${index}" name="pattern_type${index}">
|
||||
<option value="denied">Denied</option>
|
||||
<option value="allowed">Allowed</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-2">
|
||||
<select class="form-control" id="idPatternPolicy${index}" name="pattern_policy${index}">
|
||||
<option value="0">Visible</option>
|
||||
<option value="1">Hidden</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_pattern_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
$("#idPatternType"+index).selectpicker();
|
||||
$("#idPatternPolicy"+index).selectpicker();
|
||||
});
|
||||
|
||||
$("body").on("click", ".remove_pattern_btn_frm_field", function () {
|
||||
$(this).closest(".form_field_patterns_outer_row").remove();
|
||||
});
|
||||
</script>
|
||||
{{end}}
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
{{define "extra_css"}}
|
||||
<link href="{{.StaticURL}}/vendor/tempusdominus/css/tempusdominus-bootstrap-4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/bootstrap-select/css/bootstrap-select.min.css" rel="stylesheet">
|
||||
{{end}}
|
||||
|
||||
{{define "page_body"}}
|
||||
@@ -140,6 +141,36 @@
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<div class="card bg-light mb-3">
|
||||
<div class="card-header">
|
||||
<b>Groups</b>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h6 class="card-title mb-4">Group membership impart the group settings if no override exist</h6>
|
||||
<div class="form-group row">
|
||||
<label for="idPrimaryGroup" class="col-sm-2 col-form-label">Primary group</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control selectpicker" data-live-search="true" id="idPrimaryGroup" name="primary_group">
|
||||
<option value=""></option>
|
||||
{{- range .Groups}}
|
||||
<option value="{{.Name}}" {{if $.User.HasPrimaryGroup .Name}}selected{{end}}>{{.Name}}</option>
|
||||
{{- end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="idSecondaryGroup" class="col-sm-2 col-form-label">Secondary groups</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control selectpicker" data-live-search="true" id="idSecondaryGroup" name="secondary_groups" multiple>
|
||||
{{- range .Groups}}
|
||||
<option value="{{.Name}}" {{if $.User.HasSecondaryGroup .Name}}selected{{end}}>{{.Name}}</option>
|
||||
{{- end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "fshtml" .FsWrapper}}
|
||||
{{if .VirtualFolders}}
|
||||
<div class="card bg-light mb-3">
|
||||
@@ -156,7 +187,7 @@
|
||||
<input type="text" class="form-control" id="idVolderPath{{$idx}}" name="vfolder_path" placeholder="mount path, i.e. /vfolder" value="{{$val.VirtualPath}}" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<select class="form-control" id="idVfolderName{{$idx}}" name="vfolder_name">
|
||||
<select class="form-control selectpicker" data-live-search="true" id="idVfolderName{{$idx}}" name="vfolder_name">
|
||||
<option value=""></option>
|
||||
{{range $.VirtualFolders}}
|
||||
<option value="{{.Name}}" {{if eq $val.Name .Name}}selected{{end}}>{{.Name}}</option>
|
||||
@@ -189,7 +220,7 @@
|
||||
<input type="text" class="form-control" id="idVolderPath0" name="vfolder_path" placeholder="mount path, i.e. /vfolder" value="" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<select class="form-control" id="idVfolderName0" name="vfolder_name">
|
||||
<select class="form-control selectpicker" data-live-search="true" id="idVfolderName0" name="vfolder_name">
|
||||
<option value=""></option>
|
||||
{{range .VirtualFolders}}
|
||||
<option value="{{.Name}}">{{.Name}}</option>
|
||||
@@ -245,7 +276,7 @@
|
||||
<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">
|
||||
<select class="form-control selectpicker" 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>
|
||||
@@ -322,7 +353,7 @@
|
||||
<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>
|
||||
<select class="form-control selectpicker" 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}}
|
||||
@@ -343,7 +374,7 @@
|
||||
<input type="text" class="form-control" id="idSubDirPermsPath{{$idx}}" name="sub_perm_path{{$idx}}" placeholder="directory path, i.e. /dir" value="{{$dirPerms.Path}}" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<select class="form-control" id="idSubDirPermissions{{$idx}}" name="sub_perm_permissions{{$idx}}" multiple>
|
||||
<select class="form-control selectpicker" id="idSubDirPermissions{{$idx}}" name="sub_perm_permissions{{$idx}}" multiple>
|
||||
{{range $validPerm := $.ValidPerms}}
|
||||
<option value="{{$validPerm}}" {{range $perm := $dirPerms.Permissions }}{{if eq $perm $validPerm}}selected{{end}}{{end}}>{{$validPerm}}</option>
|
||||
{{end}}
|
||||
@@ -361,7 +392,7 @@
|
||||
<input type="text" class="form-control" id="idSubDirPermsPath0" name="sub_perm_path0" placeholder="directory path, i.e. /dir" value="" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<select class="form-control" id="idSubDirPermissions0" name="sub_perm_permissions0" multiple>
|
||||
<select class="form-control selectpicker" id="idSubDirPermissions0" name="sub_perm_permissions0" multiple>
|
||||
{{range $validPerm := .ValidPerms}}
|
||||
<option value="{{$validPerm}}">{{$validPerm}}</option>
|
||||
{{end}}
|
||||
@@ -394,7 +425,7 @@
|
||||
<p class="card-text">Denied entries are visible in directory listing by default, you can hide them by setting the "Hidden" policy, but please be aware that this may cause performance issues for large directories</p>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-12 form_field_patterns_outer">
|
||||
{{range $idx, $pattern := .User.GetFlatFilePatterns -}}
|
||||
{{range $idx, $pattern := .User.Filters.GetFlatFilePatterns -}}
|
||||
<div class="row form_field_patterns_outer_row">
|
||||
<div class="form-group col-md-3">
|
||||
<input type="text" class="form-control" id="idPatternPath{{$idx}}" name="pattern_path{{$idx}}" placeholder="directory path, i.e. /dir" value="{{$pattern.Path}}" maxlength="255">
|
||||
@@ -403,13 +434,13 @@
|
||||
<input type="text" class="form-control" id="idPatterns{{$idx}}" name="patterns{{$idx}}" placeholder="*.zip,?.txt" value="{{$pattern.GetCommaSeparatedPatterns}}" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-2">
|
||||
<select class="form-control" id="idPatternType{{$idx}}" name="pattern_type{{$idx}}">
|
||||
<select class="form-control selectpicker" id="idPatternType{{$idx}}" name="pattern_type{{$idx}}">
|
||||
<option value="denied" {{if $pattern.IsDenied}}selected{{end}}>Denied</option>
|
||||
<option value="allowed" {{if $pattern.IsAllowed}}selected{{end}}>Allowed</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-2">
|
||||
<select class="form-control" id="idPatternPolicy{{$idx}}" name="pattern_policy{{$idx}}">
|
||||
<select class="form-control selectpicker" id="idPatternPolicy{{$idx}}" name="pattern_policy{{$idx}}">
|
||||
<option value="0" {{if eq $pattern.DenyPolicy 0}}selected{{end}}>Visible</option>
|
||||
<option value="1" {{if eq $pattern.DenyPolicy 1}}selected{{end}}>Hidden</option>
|
||||
</select>
|
||||
@@ -429,13 +460,13 @@
|
||||
<input type="text" class="form-control" id="idPatterns0" name="patterns0" placeholder="*.zip,?.txt" value="" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-2">
|
||||
<select class="form-control" id="idPatternType0" name="pattern_type0">
|
||||
<select class="form-control selectpicker" id="idPatternType0" name="pattern_type0">
|
||||
<option value="denied">Denied</option>
|
||||
<option value="allowed">Allowed</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-2">
|
||||
<select class="form-control" id="idPatternPolicy0" name="pattern_policy0">
|
||||
<select class="form-control selectpicker" id="idPatternPolicy0" name="pattern_policy0">
|
||||
<option value="0">Visible</option>
|
||||
<option value="1">Hidden</option>
|
||||
</select>
|
||||
@@ -472,7 +503,7 @@
|
||||
<div class="form-group row">
|
||||
<label for="idProtocols" class="col-sm-2 col-form-label">Denied protocols</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control" id="idProtocols" name="denied_protocols" multiple>
|
||||
<select class="form-control selectpicker" id="idProtocols" name="denied_protocols" multiple>
|
||||
{{range $protocol := .ValidProtocols}}
|
||||
<option value="{{$protocol}}" {{range $p :=$.User.Filters.DeniedProtocols }}{{if eq $p $protocol}}selected{{end}}{{end}}>{{$protocol}}
|
||||
</option>
|
||||
@@ -484,7 +515,7 @@
|
||||
<div class="form-group row">
|
||||
<label for="idLoginMethods" class="col-sm-2 col-form-label">Denied login methods</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control" id="idLoginMethods" name="denied_login_methods" multiple aria-describedby="deniedLoginMethodsHelpBlock">
|
||||
<select class="form-control selectpicker" id="idLoginMethods" name="denied_login_methods" multiple aria-describedby="deniedLoginMethodsHelpBlock">
|
||||
{{range $method := .ValidLoginMethods}}
|
||||
<option value="{{$method}}" {{range $m :=$.User.Filters.DeniedLoginMethods }}{{if eq $m $method}}selected{{end}}{{end}}>{{$method}}
|
||||
</option>
|
||||
@@ -499,7 +530,7 @@
|
||||
<div class="form-group row">
|
||||
<label for="idTwoFactorProtocols" class="col-sm-2 col-form-label">Require two-factor auth for</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control" id="idTwoFactorProtocols" name="required_two_factor_protocols" multiple>
|
||||
<select class="form-control selectpicker" id="idTwoFactorProtocols" name="required_two_factor_protocols" multiple>
|
||||
{{range $protocol := .TwoFactorProtocols}}
|
||||
<option value="{{$protocol}}" {{range $p :=$.User.Filters.TwoFactorAuthProtocols }}{{if eq $p $protocol}}selected{{end}}{{end}}>{{$protocol}}
|
||||
</option>
|
||||
@@ -511,7 +542,7 @@
|
||||
<div class="form-group row">
|
||||
<label for="idWebClient" class="col-sm-2 col-form-label">Web client/REST API</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control" id="idWebClient" name="web_client_options" multiple>
|
||||
<select class="form-control selectpicker" id="idWebClient" name="web_client_options" multiple>
|
||||
{{range $option := .WebClientOptions}}
|
||||
<option value="{{$option}}" {{range $p :=$.User.Filters.WebClient }}{{if eq $p $option}}selected{{end}}{{end}}>{{$option}}
|
||||
</option>
|
||||
@@ -852,7 +883,7 @@
|
||||
<div class="form-group row">
|
||||
<label for="idTLSUsername" class="col-sm-2 col-form-label">TLS username</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control" id="idTLSUsername" name="tls_username" aria-describedby="tlsUsernameHelpBlock">
|
||||
<select class="form-control selectpicker" id="idTLSUsername" name="tls_username" aria-describedby="tlsUsernameHelpBlock">
|
||||
<option value="None" {{if eq .User.Filters.TLSUsername "None" }}selected{{end}}>None</option>
|
||||
<option value="CommonName" {{if eq .User.Filters.TLSUsername "CommonName" }}selected{{end}}>Common Name</option>
|
||||
</select>
|
||||
@@ -862,6 +893,23 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="idHooks" class="col-sm-2 col-form-label">Hooks</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control selectpicker" id="idHooks" name="hooks" multiple>
|
||||
<option value="external_auth_disabled" {{if .User.Filters.Hooks.ExternalAuthDisabled}}selected{{end}}>
|
||||
External auth disabled
|
||||
</option>
|
||||
<option value="pre_login_disabled" {{if .User.Filters.Hooks.PreLoginDisabled}}selected{{end}}>
|
||||
Pre-login disabled
|
||||
</option>
|
||||
<option value="check_password_disabled" {{if .User.Filters.Hooks.CheckPasswordDisabled}}selected{{end}}>
|
||||
Check password disabled
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row {{if not .CanImpersonate}}d-none{{end}}">
|
||||
<label for="idUID" class="col-sm-2 col-form-label">UID</label>
|
||||
<div class="col-sm-3">
|
||||
@@ -887,23 +935,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="idHooks" class="col-sm-2 col-form-label">Hooks</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-control" id="idHooks" name="hooks" multiple>
|
||||
<option value="external_auth_disabled" {{if .User.Filters.Hooks.ExternalAuthDisabled}}selected{{end}}>
|
||||
External auth disabled
|
||||
</option>
|
||||
<option value="pre_login_disabled" {{if .User.Filters.Hooks.PreLoginDisabled}}selected{{end}}>
|
||||
Pre-login disabled
|
||||
</option>
|
||||
<option value="check_password_disabled" {{if .User.Filters.Hooks.CheckPasswordDisabled}}selected{{end}}>
|
||||
Check password disabled
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row {{if not .User.HasExternalAuth}}d-none{{end}}">
|
||||
<label for="idExtAuthCacheTime" class="col-sm-2 col-form-label">External auth cache time</label>
|
||||
<div class="col-sm-10">
|
||||
@@ -950,8 +981,10 @@
|
||||
{{define "extra_js"}}
|
||||
<script src="{{.StaticURL}}/vendor/moment/js/moment.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/tempusdominus/js/tempusdominus-bootstrap-4.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/bootstrap-select/js/bootstrap-select.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
$.fn.selectpicker.Constructor.BootstrapVersion = '4';
|
||||
{{if .Error}}
|
||||
$('#accordionUser .collapse').removeAttr("data-parent").collapse('show');
|
||||
{{end}}
|
||||
@@ -987,273 +1020,62 @@
|
||||
});
|
||||
|
||||
onFilesystemChanged('{{.User.FsConfig.Provider.Name}}');
|
||||
|
||||
$("body").on("click", ".add_new_pk_field_btn", function () {
|
||||
var index = $(".form_field_pk_outer").find(".form_field_pk_outer_row").length;
|
||||
while (document.getElementById("idPublicKey"+index) != null){
|
||||
index++;
|
||||
}
|
||||
$(".form_field_pk_outer").append(`
|
||||
<div class="row form_field_pk_outer_row">
|
||||
<div class="form-group col-md-11">
|
||||
<textarea class="form-control" id="idPublicKey${index}" name="public_keys" rows="3"
|
||||
placeholder="Paste your public key here"></textarea>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_pk_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
|
||||
$("body").on("click", ".remove_pk_btn_frm_field", function () {
|
||||
$(this).closest(".form_field_pk_outer_row").remove();
|
||||
});
|
||||
|
||||
$("body").on("click", ".add_new_dirperms_field_btn", function () {
|
||||
var index = $(".form_field_dirperms_outer").find(".form_field_dirperms_outer_row").length;
|
||||
while (document.getElementById("idSubDirPermsPath"+index) != null){
|
||||
index++;
|
||||
}
|
||||
$(".form_field_dirperms_outer").append(`
|
||||
<div class="row form_field_dirperms_outer_row">
|
||||
<div class="form-group col-md-8">
|
||||
<input type="text" class="form-control" id="idSubDirPermsPath${index}" name="sub_perm_path${index}" placeholder="directory path, i.e. /dir" value="" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<select class="form-control" id="idSubDirPermissions${index}" name="sub_perm_permissions${index}" multiple>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_dirperms_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
{{range .ValidPerms}}
|
||||
$("#idSubDirPermissions"+index).append($('<option>').val('{{.}}').text('{{.}}'));
|
||||
{{end}}
|
||||
});
|
||||
|
||||
$("body").on("click", ".remove_dirperms_btn_frm_field", function () {
|
||||
$(this).closest(".form_field_dirperms_outer_row").remove();
|
||||
});
|
||||
|
||||
$("body").on("click", ".add_new_vfolder_field_btn", function () {
|
||||
var index = $(".form_field_vfolders_outer").find(".form_field_vfolder_outer_row").length;
|
||||
while (document.getElementById("idVolderPath"+index) != null){
|
||||
index++;
|
||||
}
|
||||
$(".form_field_vfolders_outer").append(`
|
||||
<div class="row form_field_vfolder_outer_row">
|
||||
<div class="form-group col-md-3">
|
||||
<input type="text" class="form-control" id="idVolderPath${index}" name="vfolder_path" placeholder="mount path, i.e. /vfolder" value="" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<select class="form-control" id="idVfolderName${index}" name="vfolder_name">
|
||||
<option value=""></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<input type="number" class="form-control" id="idVfolderQuotaSize${index}" name="vfolder_quota_size"
|
||||
value="" min="-1" aria-describedby="vqsHelpBlock${index}">
|
||||
<small id="vqsHelpBlock${index}" class="form-text text-muted">
|
||||
Quota size (bytes)
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group col-md-2">
|
||||
<input type="number" class="form-control" id="idVfolderQuotaFiles${index}" name="vfolder_quota_files"
|
||||
value="" min="-1" aria-describedby="vqfHelpBlock${index}">
|
||||
<small id="vqfHelpBlock${index}" class="form-text text-muted">
|
||||
Quota files
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_vfolder_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
{{range .VirtualFolders}}
|
||||
$("#idVfolderName"+index).append($('<option>').val('{{.Name}}').text('{{.Name}}'));
|
||||
{{end}}
|
||||
});
|
||||
|
||||
$("body").on("click", ".remove_vfolder_btn_frm_field", function () {
|
||||
$(this).closest(".form_field_vfolder_outer_row").remove();
|
||||
});
|
||||
|
||||
$("body").on("click", ".add_new_bwlimit_field_btn", function () {
|
||||
var index = $(".form_field_bwlimits_outer").find(".form_field_bwlimits_outer_row").length;
|
||||
while (document.getElementById("idBandwidthLimitSources"+index) != null){
|
||||
index++;
|
||||
}
|
||||
$(".form_field_bwlimits_outer").append(`
|
||||
<div class="row form_field_bwlimits_outer_row">
|
||||
<div class="form-group col-md-8">
|
||||
<textarea class="form-control" id="idBandwidthLimitSources0" name="bandwidth_limit_sources${index}" rows="4" placeholder=""
|
||||
aria-describedby="bwLimitSourcesHelpBlock${index}"></textarea>
|
||||
<small id="bwLimitSourcesHelpBlock${index}" class="form-text text-muted">
|
||||
Comma separated IP/Mask in CIDR format, example: "192.168.1.0/24,10.8.0.100/32"
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idUploadBandwidthSource${index}" name="upload_bandwidth_source${index}"
|
||||
placeholder="" value="" min="0" aria-describedby="ulHelpBlock${index}">
|
||||
<small id="ulHelpBlock${index}" class="form-text text-muted">
|
||||
UL (KB/s). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idDownloadBandwidthSource${index}" name="download_bandwidth_source${index}"
|
||||
placeholder="" value="" min="0" aria-describedby="dlHelpBlock${index}">
|
||||
<small id="dlHelpBlock${index}" class="form-text text-muted">
|
||||
DL (KB/s). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_bwlimit_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
|
||||
$("body").on("click", ".remove_bwlimit_btn_frm_field", function () {
|
||||
$(this).closest(".form_field_bwlimits_outer_row").remove();
|
||||
});
|
||||
|
||||
$("body").on("click", ".add_new_dtlimit_field_btn", function () {
|
||||
var index = $(".form_field_dtlimits_outer").find(".form_field_dtlimits_outer_row").length;
|
||||
while (document.getElementById("idDataTransferLimitSources"+index) != null){
|
||||
index++;
|
||||
}
|
||||
$(".form_field_dtlimits_outer").append(`
|
||||
<div class="row form_field_dtlimits_outer_row">
|
||||
<div class="form-group col-md-5">
|
||||
<textarea class="form-control" id="idDataTransferLimitSources${index}" name="data_transfer_limit_sources${index}" rows="4" placeholder=""
|
||||
aria-describedby="dtLimitSourcesHelpBlock${index}"></textarea>
|
||||
<small id="dtLimitSourcesHelpBlock${index}" class="form-text text-muted">
|
||||
Comma separated IP/Mask in CIDR format, example: "192.168.1.0/24,10.8.0.100/32"
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idUploadTransferSource${index}" name="upload_data_transfer_source${index}"
|
||||
placeholder="" value="" min="0" aria-describedby="ulDtHelpBlock${index}">
|
||||
<small id="ulDtHelpBlock${index}" class="form-text text-muted">
|
||||
UL (MB). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idDownloadTransferSource${index}" name="download_data_transfer_source${index}"
|
||||
placeholder="" value="" min="0" aria-describedby="dlDtHelpBlock${index}">
|
||||
<small id="dlDtHelpBlock${index}" class="form-text text-muted">
|
||||
DL (MB). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="form-group">
|
||||
<input type="number" class="form-control" id="idTotalTransferSource${index}" name="total_data_transfer_source${index}"
|
||||
placeholder="" value="" min="0" aria-describedby="totalDtHelpBlock${index}">
|
||||
<small id="totalDtHelpBlock${index}" class="form-text text-muted">
|
||||
Total (MB). 0 means no limit
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_dtlimit_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
|
||||
$("body").on("click", ".remove_dtlimit_btn_frm_field", function () {
|
||||
$(this).closest(".form_field_dtlimits_outer_row").remove();
|
||||
});
|
||||
|
||||
$("body").on("click", ".add_new_pattern_field_btn", function () {
|
||||
var index = $(".form_field_patterns_outer").find(".form_field_patterns_outer_row").length;
|
||||
while (document.getElementById("idPatternPath"+index) != null){
|
||||
index++;
|
||||
}
|
||||
$(".form_field_patterns_outer").append(`
|
||||
<div class="row form_field_patterns_outer_row">
|
||||
<div class="form-group col-md-3">
|
||||
<input type="text" class="form-control" id="idPatternPath${index}" name="pattern_path${index}" placeholder="directory path, i.e. /dir" value="" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
<input type="text" class="form-control" id="idPatterns${index}" name="patterns${index}" placeholder="*.zip,?.txt" value="" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-2">
|
||||
<select class="form-control" id="idPatternType${index}" name="pattern_type${index}">
|
||||
<option value="denied">Denied</option>
|
||||
<option value="allowed">Allowed</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-2">
|
||||
<select class="form-control" id="idPatternPolicy${index}" name="pattern_policy${index}">
|
||||
<option value="0">Visible</option>
|
||||
<option value="1">Hidden</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_pattern_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
|
||||
$("body").on("click", ".remove_pattern_btn_frm_field", function () {
|
||||
$(this).closest(".form_field_patterns_outer_row").remove();
|
||||
});
|
||||
|
||||
$("body").on("click", ".add_new_tpl_user_field_btn", function () {
|
||||
var index = $(".form_field_tpl_users_outer").find(".form_field_tpl_user_outer_row").length;
|
||||
while (document.getElementById("idTplUsername"+index) != null){
|
||||
index++;
|
||||
}
|
||||
$(".form_field_tpl_users_outer").append(`
|
||||
<div class="row form_field_tpl_user_outer_row">
|
||||
<div class="form-group col-md-3">
|
||||
<input type="text" class="form-control" id="idTplUsername${index}" name="tpl_username" placeholder="Username" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<input type="password" class="form-control" id="idTplPassword${index}" name="tpl_password" placeholder="Password" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-5">
|
||||
<textarea class="form-control" id="idTplPublicKey${index}" name="tpl_public_keys" rows="5"
|
||||
placeholder="Paste your public key here"></textarea>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_tpl_user_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
|
||||
$("body").on("click", ".remove_tpl_user_btn_frm_field", function () {
|
||||
$(this).closest(".form_field_tpl_user_outer_row").remove();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
{{template "fsjs"}}
|
||||
$("body").on("click", ".add_new_pk_field_btn", function () {
|
||||
var index = $(".form_field_pk_outer").find(".form_field_pk_outer_row").length;
|
||||
while (document.getElementById("idPublicKey"+index) != null){
|
||||
index++;
|
||||
}
|
||||
$(".form_field_pk_outer").append(`
|
||||
<div class="row form_field_pk_outer_row">
|
||||
<div class="form-group col-md-11">
|
||||
<textarea class="form-control" id="idPublicKey${index}" name="public_keys" rows="3"
|
||||
placeholder="Paste your public key here"></textarea>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_pk_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
|
||||
$("body").on("click", ".remove_pk_btn_frm_field", function () {
|
||||
$(this).closest(".form_field_pk_outer_row").remove();
|
||||
});
|
||||
|
||||
$("body").on("click", ".add_new_tpl_user_field_btn", function () {
|
||||
var index = $(".form_field_tpl_users_outer").find(".form_field_tpl_user_outer_row").length;
|
||||
while (document.getElementById("idTplUsername"+index) != null){
|
||||
index++;
|
||||
}
|
||||
$(".form_field_tpl_users_outer").append(`
|
||||
<div class="row form_field_tpl_user_outer_row">
|
||||
<div class="form-group col-md-3">
|
||||
<input type="text" class="form-control" id="idTplUsername${index}" name="tpl_username" placeholder="Username" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<input type="password" class="form-control" id="idTplPassword${index}" name="tpl_password" placeholder="Password" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group col-md-5">
|
||||
<textarea class="form-control" id="idTplPublicKey${index}" name="tpl_public_keys" rows="5"
|
||||
placeholder="Paste your public key here"></textarea>
|
||||
</div>
|
||||
<div class="form-group col-md-1">
|
||||
<button class="btn btn-circle btn-danger remove_tpl_user_btn_frm_field">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
|
||||
$("body").on("click", ".remove_tpl_user_btn_frm_field", function () {
|
||||
$(this).closest(".form_field_tpl_user_outer_row").remove();
|
||||
});
|
||||
</script>
|
||||
{{template "fsjs"}}
|
||||
{{template "shared_user_group" .}}
|
||||
{{end}}
|
||||
|
||||
Reference in New Issue
Block a user