Skip to content

Commit 72ba54b

Browse files
committed
WebAdmin: add CSV export for users, groups, folders, admins, roles
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
1 parent 18bf0c6 commit 72ba54b

File tree

7 files changed

+721
-1
lines changed

7 files changed

+721
-1
lines changed

static/vendor/file-saver/FileSaver.min.js

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

static/vendor/papaparse/papaparse.min.js

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

templates/webadmin/admins.html

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ <h3 data-i18n="admin.view_manage" class="card-title section-title">View and mana
3636
<i class="ki-solid ki-magnifier fs-1 position-absolute ms-6"></i>
3737
<input name="search" data-i18n="[placeholder]general.search" type="text" data-table-filter="search"
3838
class="form-control rounded-1 w-250px ps-15 me-5" placeholder="Search" />
39+
<button id="export_button" type="button" class="btn btn-light-primary ms-3" data-table-filter="export">
40+
<span data-i18n="general.export" class="indicator-label">
41+
Export
42+
</span>
43+
<span data-i18n="general.wait" class="indicator-progress">
44+
Please wait...
45+
<span class="spinner-border spinner-border-sm align-middle ms-2"></span>
46+
</span>
47+
</button>
3948
</div>
4049

4150
<div class="d-flex justify-content-end my-2" data-table-toolbar="base">
@@ -112,6 +121,8 @@ <h3 data-i18n="admin.view_manage" class="card-title section-title">View and mana
112121
{{- end}}
113122
{{- define "extra_js"}}
114123
<script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/assets/plugins/custom/datatables/datatables.bundle.js"></script>
124+
<script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/vendor/papaparse/papaparse.min.js"></script>
125+
<script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/vendor/file-saver/FileSaver.min.js"></script>
115126
<script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
116127
function deleteAction(username) {
117128
ModalAlert.fire({
@@ -453,6 +464,104 @@ <h3 data-i18n="admin.view_manage" class="card-title section-title">View and mana
453464
handleColVisibilityCheckbox($('#checkColRole'), 4);
454465
handleColVisibilityCheckbox($('#checkCol2FA'), 5);
455466
handleColVisibilityCheckbox($('#checkColDesc'), 6);
467+
468+
const exportButton = $(document.querySelector('[data-table-filter="export"]'));
469+
exportButton.on('click', function(e){
470+
e.preventDefault();
471+
this.blur();
472+
this.setAttribute('data-kt-indicator', 'on');
473+
this.disabled = true;
474+
475+
let data = [];
476+
dt.rows({ search: 'applied' }).every(function (rowIdx, tableLoop, rowLoop){
477+
let line = {};
478+
let rowData = dt.row(rowIdx).data();
479+
let filters = rowData["filters"];
480+
481+
line["Username"] = rowData["username"];
482+
let status = "Inactive";
483+
if (rowData["status"] == 1){
484+
status = "Active";
485+
}
486+
line["Status"] = status;
487+
line["Permissions"] = rowData["permissions"].join(", ");
488+
489+
if (rowData["created_at"]) {
490+
line["Created At"] = moment(rowData["created_at"]).format("YYYY-MM-DD HH:mm");
491+
} else {
492+
line["Created At"] = "";
493+
}
494+
if (rowData["updated_at"]) {
495+
line["Updated At"] = moment(rowData["updated_at"]).format("YYYY-MM-DD HH:mm");
496+
} else {
497+
line["Updated At"] = "";
498+
}
499+
if (rowData["last_login"]) {
500+
line["Last Login"] = moment(rowData["last_login"]).format("YYYY-MM-DD HH:mm");
501+
} else {
502+
line["Last Login"] = "";
503+
}
504+
if (rowData["email"]){
505+
line["Email"] = rowData["email"];
506+
} else {
507+
line["Email"] = "";
508+
}
509+
let totpConfig = filters["totp_config"];
510+
if (totpConfig && totpConfig["enabled"]){
511+
line["Two-factor auth"] = "Enabled";
512+
} else {
513+
line["Two-factor auth"] = "Disabled";
514+
}
515+
if (filters["allow_list"]){
516+
line["Allow List"] = filters["allow_list"].join(", ");
517+
} else {
518+
line["Allow List"] = "";
519+
}
520+
let groups = [];
521+
let rowGroups = rowData["groups"];
522+
if (rowGroups){
523+
for (i = 0; i < rowGroups.length; i++ ){
524+
groups.push(rowGroups[i].name);
525+
}
526+
}
527+
line["Groups"] = groups.join(", ");
528+
if (rowData["role"]){
529+
line["Role"] = rowData["role"];
530+
} else {
531+
line["Role"] = "";
532+
}
533+
if (rowData["description"]){
534+
line["Description"] = rowData["description"];
535+
} else {
536+
line["Description"] = "";
537+
}
538+
if (rowData["additional_info"]){
539+
line["Additional info"] = rowData["additional_info"];
540+
} else {
541+
line["Additional info"] = "";
542+
}
543+
544+
data.push(line);
545+
});
546+
547+
let csv = Papa.unparse(data, {
548+
quotes: false,
549+
quoteChar: '"',
550+
escapeChar: '"',
551+
delimiter: ",",
552+
header: true,
553+
newline: "\r\n",
554+
skipEmptyLines: false,
555+
columns: null,
556+
escapeFormulae: true
557+
});
558+
let blob = new Blob([csv], {type: "text/csv"});
559+
let ts = moment().format("YYYY_MM_DD_HH_mm_ss");
560+
saveAs(blob, `admins_${ts}.csv`);
561+
562+
this.removeAttribute('data-kt-indicator');
563+
this.disabled = false;
564+
});
456565
}
457566

458567
function handleRowActions() {

templates/webadmin/folders.html

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ <h3 data-i18n="virtual_folders.view_manage" class="card-title section-title">Vie
3636
<i class="ki-solid ki-magnifier fs-1 position-absolute ms-6"></i>
3737
<input name="search" data-i18n="[placeholder]general.search" type="text" data-table-filter="search"
3838
class="form-control rounded-1 w-250px ps-15 me-5" placeholder="Search" />
39+
<button id="export_button" type="button" class="btn btn-light-primary ms-3" data-table-filter="export">
40+
<span data-i18n="general.export" class="indicator-label">
41+
Export
42+
</span>
43+
<span data-i18n="general.wait" class="indicator-progress">
44+
Please wait...
45+
<span class="spinner-border spinner-border-sm align-middle ms-2"></span>
46+
</span>
47+
</button>
3948
</div>
4049

4150
<div class="d-flex justify-content-end my-2" data-table-toolbar="base">
@@ -97,6 +106,8 @@ <h3 data-i18n="virtual_folders.view_manage" class="card-title section-title">Vie
97106
{{- end}}
98107
{{- define "extra_js"}}
99108
<script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/assets/plugins/custom/datatables/datatables.bundle.js"></script>
109+
<script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/vendor/papaparse/papaparse.min.js"></script>
110+
<script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/vendor/file-saver/FileSaver.min.js"></script>
100111
<script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
101112
function deleteAction(name) {
102113
ModalAlert.fire({
@@ -375,6 +386,83 @@ <h3 data-i18n="virtual_folders.view_manage" class="card-title section-title">Vie
375386
handleColVisibilityCheckbox($('#checkColQuota'), 2);
376387
handleColVisibilityCheckbox($('#checkColAssociations'), 3);
377388
handleColVisibilityCheckbox($('#checkColDesc'), 4);
389+
390+
const exportButton = $(document.querySelector('[data-table-filter="export"]'));
391+
exportButton.on('click', function(e){
392+
e.preventDefault();
393+
this.blur();
394+
this.setAttribute('data-kt-indicator', 'on');
395+
this.disabled = true;
396+
397+
let data = [];
398+
dt.rows({ search: 'applied' }).every(function (rowIdx, tableLoop, rowLoop){
399+
let line = {};
400+
let rowData = dt.row(rowIdx).data();
401+
402+
line["Name"] = rowData["name"];
403+
let fsProvider = "Local storage";
404+
if (rowData["mapped_path"]){
405+
fsProvider+=": "+rowData["mapped_path"];
406+
}
407+
switch (rowData["filesystem"]["provider"]){
408+
case 1:
409+
fsProvider = "S3 Compatible";
410+
break;
411+
case 2:
412+
fsProvider = "Google Cloud Storage";
413+
break;
414+
case 3:
415+
fsProvider = "Azure Blob";
416+
break;
417+
case 4:
418+
fsProvider = "Local storage encrypted: "+rowData["home_dir"];
419+
break;
420+
case 5:
421+
fsProvider = "SFTP";
422+
break;
423+
case 6:
424+
fsProvider = "HTTP";
425+
break;
426+
}
427+
line["Filesystem"] = fsProvider;
428+
429+
if (rowData["users"]){
430+
line["Users"] = rowData["users"].join(", ");
431+
} else {
432+
line["Users"] = "";
433+
}
434+
if (rowData["groups"]){
435+
line["Groups"] = rowData["groups"].join(", ");
436+
} else {
437+
line["Groups"] = "";
438+
}
439+
if (rowData["description"]){
440+
line["Description"] = rowData["description"];
441+
} else {
442+
line["Description"] = "";
443+
}
444+
445+
data.push(line);
446+
});
447+
448+
let csv = Papa.unparse(data, {
449+
quotes: false,
450+
quoteChar: '"',
451+
escapeChar: '"',
452+
delimiter: ",",
453+
header: true,
454+
newline: "\r\n",
455+
skipEmptyLines: false,
456+
columns: null,
457+
escapeFormulae: true
458+
});
459+
let blob = new Blob([csv], {type: "text/csv"});
460+
let ts = moment().format("YYYY_MM_DD_HH_mm_ss");
461+
saveAs(blob, `folders_${ts}.csv`);
462+
463+
this.removeAttribute('data-kt-indicator');
464+
this.disabled = false;
465+
});
378466
}
379467

380468
function handleRowActions() {

0 commit comments

Comments
 (0)