feat: add test button to create channel form using ad-hoc smtp test endpoint
- Add TestSmtpCommand and TestSmtpHandler for ad-hoc smtp testing without saving - Add POST /admin/channels/test-smtp endpoint accepting raw smtp settings - Show Test button on both Create and Edit forms - Test reads current form values so channel can be tested before saving
This commit is contained in:
@@ -121,82 +121,90 @@
|
||||
<button type="submit" form="channelForm" class="btn btn-primary">
|
||||
<i class="bi bi-floppy me-1"></i> Save
|
||||
</button>
|
||||
@if (!Model.IsNew)
|
||||
{
|
||||
<button type="button" class="btn btn-success" id="testModalBtn">
|
||||
<i class="bi bi-send me-1"></i> Test
|
||||
</button>
|
||||
}
|
||||
<button type="button" class="btn btn-success" id="testModalBtn">
|
||||
<i class="bi bi-send me-1"></i> Test
|
||||
</button>
|
||||
<a href="/admin/channels" class="btn btn-secondary">
|
||||
<i class="bi bi-x-lg me-1"></i> Cancel
|
||||
</a>
|
||||
}
|
||||
</form>
|
||||
|
||||
@if (!Model.IsNew)
|
||||
{
|
||||
<div class="modal fade" id="testModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><i class="bi bi-send me-2"></i>Send Test Email</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<label for="testToEmail" class="form-label fw-semibold">Recipient Email</label>
|
||||
<input type="email" id="testToEmail" class="form-control" placeholder="you@example.com" />
|
||||
<div id="testResult" class="mt-3" style="display:none"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-success" id="testSendBtn" onclick="sendTestEmail('@Model.Id')">
|
||||
<i class="bi bi-send me-1"></i> Send
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal fade" id="testModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><i class="bi bi-send me-2"></i>Send Test Email</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="text-muted small">Tests the current form settings — no need to save first.</p>
|
||||
<label for="testToEmail" class="form-label fw-semibold">Recipient Email</label>
|
||||
<input type="email" id="testToEmail" class="form-control" placeholder="you@example.com" />
|
||||
<div id="testResult" class="mt-3" style="display:none"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-success" id="testSendBtn" onclick="sendTestEmail()">
|
||||
<i class="bi bi-send me-1"></i> Send
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('click', function (e) {
|
||||
if (e.target.closest('#testModalBtn')) {
|
||||
bootstrap.Modal.getOrCreateInstance(document.getElementById('testModal')).show();
|
||||
}
|
||||
});
|
||||
|
||||
async function sendTestEmail(channelId) {
|
||||
const toEmail = document.getElementById('testToEmail').value.trim();
|
||||
const resultDiv = document.getElementById('testResult');
|
||||
const sendBtn = document.getElementById('testSendBtn');
|
||||
|
||||
if (!toEmail) {
|
||||
resultDiv.style.display = 'block';
|
||||
resultDiv.innerHTML = '<div class="alert alert-warning mb-0">Please enter a recipient email.</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
sendBtn.disabled = true;
|
||||
sendBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span> Sending…';
|
||||
resultDiv.style.display = 'none';
|
||||
|
||||
try {
|
||||
const resp = await fetch(`/admin/channels/${channelId}/test`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ toEmail })
|
||||
});
|
||||
const data = await resp.json();
|
||||
resultDiv.style.display = 'block';
|
||||
resultDiv.innerHTML = data.success
|
||||
? `<div class="alert alert-success mb-0"><i class="bi bi-check-circle me-1"></i>${data.message}</div>`
|
||||
: `<div class="alert alert-danger mb-0"><i class="bi bi-x-circle me-1"></i>${data.message}</div>`;
|
||||
} catch (e) {
|
||||
resultDiv.style.display = 'block';
|
||||
resultDiv.innerHTML = `<div class="alert alert-danger mb-0">Request failed: ${e.message}</div>`;
|
||||
} finally {
|
||||
sendBtn.disabled = false;
|
||||
sendBtn.innerHTML = '<i class="bi bi-send me-1"></i> Send';
|
||||
}
|
||||
<script>
|
||||
document.addEventListener('click', function (e) {
|
||||
if (e.target.closest('#testModalBtn')) {
|
||||
document.getElementById('testResult').style.display = 'none';
|
||||
bootstrap.Modal.getOrCreateInstance(document.getElementById('testModal')).show();
|
||||
}
|
||||
</script>
|
||||
}
|
||||
});
|
||||
|
||||
async function sendTestEmail() {
|
||||
const toEmail = document.getElementById('testToEmail').value.trim();
|
||||
const resultDiv = document.getElementById('testResult');
|
||||
const sendBtn = document.getElementById('testSendBtn');
|
||||
|
||||
if (!toEmail) {
|
||||
resultDiv.style.display = 'block';
|
||||
resultDiv.innerHTML = '<div class="alert alert-warning mb-0">Please enter a recipient email.</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
const form = document.getElementById('channelForm');
|
||||
const payload = {
|
||||
host: form.querySelector('[name="Host"]').value,
|
||||
port: parseInt(form.querySelector('[name="Port"]').value, 10),
|
||||
username: form.querySelector('[name="Username"]').value,
|
||||
password: form.querySelector('[name="Password"]').value,
|
||||
useSsl: form.querySelector('[name="UseSsl"]').checked,
|
||||
fromEmail: form.querySelector('[name="FromEmail"]').value,
|
||||
fromName: form.querySelector('[name="FromName"]').value,
|
||||
toEmail
|
||||
};
|
||||
|
||||
sendBtn.disabled = true;
|
||||
sendBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span> Sending…';
|
||||
resultDiv.style.display = 'none';
|
||||
|
||||
try {
|
||||
const resp = await fetch('/admin/channels/test-smtp', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
const data = await resp.json();
|
||||
resultDiv.style.display = 'block';
|
||||
resultDiv.innerHTML = data.success
|
||||
? `<div class="alert alert-success mb-0"><i class="bi bi-check-circle me-1"></i>${data.message}</div>`
|
||||
: `<div class="alert alert-danger mb-0"><i class="bi bi-x-circle me-1"></i>${data.message}</div>`;
|
||||
} catch (e) {
|
||||
resultDiv.style.display = 'block';
|
||||
resultDiv.innerHTML = `<div class="alert alert-danger mb-0">Request failed: ${e.message}</div>`;
|
||||
} finally {
|
||||
sendBtn.disabled = false;
|
||||
sendBtn.innerHTML = '<i class="bi bi-send me-1"></i> Send';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user