Skip to content

Commit 582c2a9

Browse files
committed
gdrive: enforce at least one path mapping
1 parent 6db0aaa commit 582c2a9

File tree

2 files changed

+90
-3
lines changed

2 files changed

+90
-3
lines changed

internal/web/handlers/triggers.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,10 @@ func (h *Handlers) TriggerCreate(w http.ResponseWriter, r *http.Request) {
239239

240240
mappingIDs := r.Form["gdrive_path_rewrite_from_id[]"]
241241
mappingTargets := r.Form["gdrive_path_rewrite_to[]"]
242+
if !hasGDrivePathMapping(mappingIDs, mappingTargets) {
243+
respondError(http.StatusBadRequest, "At least one Google Drive path mapping is required")
244+
return
245+
}
242246
mappings, err := h.resolveGDrivePathMappings(r.Context(), accountID, driveID, mappingIDs, mappingTargets)
243247
if err != nil {
244248
respondError(http.StatusBadRequest, "Invalid Google Drive path mapping: "+err.Error())
@@ -562,6 +566,10 @@ func (h *Handlers) TriggerUpdate(w http.ResponseWriter, r *http.Request) {
562566

563567
mappingIDs := r.Form["gdrive_path_rewrite_from_id[]"]
564568
mappingTargets := r.Form["gdrive_path_rewrite_to[]"]
569+
if !hasGDrivePathMapping(mappingIDs, mappingTargets) {
570+
respondError(http.StatusBadRequest, "At least one Google Drive path mapping is required", "/triggers/"+idStr)
571+
return
572+
}
565573
mappings, err := h.resolveGDrivePathMappings(r.Context(), accountID, driveID, mappingIDs, mappingTargets)
566574
if err != nil {
567575
respondError(http.StatusBadRequest, "Invalid Google Drive path mapping: "+err.Error(), "/triggers/"+idStr)
@@ -827,6 +835,21 @@ func parsePathList(r *http.Request, fieldName string) []string {
827835
return paths
828836
}
829837

838+
func hasGDrivePathMapping(fromIDs, toPaths []string) bool {
839+
max := len(fromIDs)
840+
if len(toPaths) < max {
841+
max = len(toPaths)
842+
}
843+
for i := 0; i < max; i++ {
844+
fromID := strings.TrimSpace(fromIDs[i])
845+
toPath := strings.TrimSpace(toPaths[i])
846+
if fromID != "" && toPath != "" {
847+
return true
848+
}
849+
}
850+
return false
851+
}
852+
830853
func boolPtr(value bool) *bool {
831854
return &value
832855
}

internal/web/templates/triggers.html

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ <h1 class="text-2xl font-semibold text-gray-900 dark:text-white">New Trigger</h1
166166
</select>
167167
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Choose My Drive or a shared drive for this trigger.</p>
168168
</div>
169-
<p class="text-xs text-gray-500 dark:text-gray-400">This trigger always monitors the full drive. Use Include Paths below to scope what gets processed.</p>
169+
<p class="text-xs text-gray-500 dark:text-gray-400">This trigger always monitors the full drive. Add at least one path mapping below to process files.</p>
170170
</div>
171171

172172
<div id="gdrive-mapping-modal" class="fixed inset-0 z-50 hidden items-center justify-center bg-gray-900/60 px-4">
@@ -239,7 +239,7 @@ <h4 class="text-sm font-medium text-gray-900 dark:text-white">Authentication</h4
239239
<div class="flex items-center justify-between mb-2">
240240
<div>
241241
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Path Mapping (Google Drive)</label>
242-
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Map a Drive folder to a local path using the folder picker.</p>
242+
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Map a Drive folder to a local path using the folder picker. At least one mapping is required.</p>
243243
</div>
244244
<button type="button" id="gdrive-add-path-rewrite" class="btn-secondary text-xs">
245245
Add Mapping
@@ -581,6 +581,37 @@ <h4 class="text-sm font-medium text-gray-900 dark:text-white mb-4">File Stabilit
581581
return true;
582582
}
583583

584+
function validateGDriveMappings() {
585+
const typeSelect = document.getElementById('type');
586+
if (!typeSelect || typeSelect.value !== 'gdrive') {
587+
return true;
588+
}
589+
const list = document.getElementById('gdrive-path-rewrites-list');
590+
if (!list) {
591+
return true;
592+
}
593+
const rows = list.querySelectorAll('[data-role="gdrive-map-row"]');
594+
let hasMapping = false;
595+
596+
rows.forEach((row) => {
597+
const fromInput = row.querySelector('[data-role="gdrive-map-from-id"]');
598+
const toInput = row.querySelector('[data-role="gdrive-map-to"]');
599+
if (!fromInput || !toInput) {
600+
return;
601+
}
602+
if (fromInput.value.trim() !== '' && toInput.value.trim() !== '') {
603+
hasMapping = true;
604+
}
605+
});
606+
607+
if (!hasMapping) {
608+
showAlertModal('error', 'Missing Path Mapping', 'Add at least one Google Drive path mapping.');
609+
return false;
610+
}
611+
612+
return true;
613+
}
614+
584615
function handleTriggerFormSubmit(event, listId) {
585616
if (event) {
586617
event.preventDefault();
@@ -595,6 +626,9 @@ <h4 class="text-sm font-medium text-gray-900 dark:text-white mb-4">File Stabilit
595626
if (listId && !validatePathRewrites(listId)) {
596627
return false;
597628
}
629+
if (!validateGDriveMappings()) {
630+
return false;
631+
}
598632
if (!form.checkValidity()) {
599633
form.reportValidity();
600634
return false;
@@ -1069,7 +1103,7 @@ <h3 class="text-lg font-medium text-gray-900 dark:text-white mb-4">Change Trigge
10691103
<div class="flex items-center justify-between mb-2">
10701104
<div>
10711105
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Path Mapping (Google Drive)</label>
1072-
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Map a Drive folder to a local path using the folder picker.</p>
1106+
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Map a Drive folder to a local path using the folder picker. At least one mapping is required.</p>
10731107
</div>
10741108
<button type="button" id="gdrive-add-path-rewrite" class="btn-secondary text-xs">
10751109
Add Mapping
@@ -1154,6 +1188,33 @@ <h3 class="text-lg font-medium text-gray-900 dark:text-white mb-4">Change Trigge
11541188
return true;
11551189
}
11561190

1191+
function validateGDriveMappings() {
1192+
const list = document.getElementById('gdrive-path-rewrites-list');
1193+
if (!list) {
1194+
return true;
1195+
}
1196+
const rows = list.querySelectorAll('[data-role="gdrive-map-row"]');
1197+
let hasMapping = false;
1198+
1199+
rows.forEach((row) => {
1200+
const fromInput = row.querySelector('[data-role="gdrive-map-from-id"]');
1201+
const toInput = row.querySelector('[data-role="gdrive-map-to"]');
1202+
if (!fromInput || !toInput) {
1203+
return;
1204+
}
1205+
if (fromInput.value.trim() !== '' && toInput.value.trim() !== '') {
1206+
hasMapping = true;
1207+
}
1208+
});
1209+
1210+
if (!hasMapping) {
1211+
showAlertModal('error', 'Missing Path Mapping', 'Add at least one Google Drive path mapping.');
1212+
return false;
1213+
}
1214+
1215+
return true;
1216+
}
1217+
11571218
function handleTriggerFormSubmit(event) {
11581219
if (event) {
11591220
event.preventDefault();
@@ -1168,6 +1229,9 @@ <h3 class="text-lg font-medium text-gray-900 dark:text-white mb-4">Change Trigge
11681229
if (!validateEditPathRewrites()) {
11691230
return false;
11701231
}
1232+
if (!validateGDriveMappings()) {
1233+
return false;
1234+
}
11711235
if (!form.checkValidity()) {
11721236
form.reportValidity();
11731237
return false;

0 commit comments

Comments
 (0)