fix: resolve all architecture validation errors (62 -> 0)
Major refactoring to achieve zero architecture violations: API Layer: - vendor/settings.py: Move validation to Pydantic field validators (tax rate, delivery method, boost sort, preorder days, languages, locales) - admin/email_templates.py: Add Pydantic response models (TemplateListResponse, CategoriesResponse) - shop/auth.py: Move password reset logic to CustomerService Service Layer: - customer_service.py: Add password reset methods (get_customer_for_password_reset, validate_and_reset_password) Exception Layer: - customer.py: Add InvalidPasswordResetTokenException, PasswordTooShortException Frontend: - admin/email-templates.js: Use apiClient, Utils.showToast() - vendor/email-templates.js: Use apiClient, parent init pattern Templates: - admin/email-templates.html: Fix block name to extra_scripts - shop/base.html: Add language default filter Tooling: - validate_architecture.py: Fix LANG-001 false positive for SUPPORTED_LANGUAGES and SUPPORTED_LOCALES blocks 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -55,22 +55,16 @@ function emailTemplatesPage() {
|
||||
async loadData() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const [templatesRes, categoriesRes] = await Promise.all([
|
||||
fetch('/api/v1/admin/email-templates'),
|
||||
fetch('/api/v1/admin/email-templates/categories')
|
||||
const [templatesData, categoriesData] = await Promise.all([
|
||||
apiClient.get('/admin/email-templates'),
|
||||
apiClient.get('/admin/email-templates/categories')
|
||||
]);
|
||||
|
||||
if (templatesRes.ok) {
|
||||
this.templates = await templatesRes.json();
|
||||
}
|
||||
|
||||
if (categoriesRes.ok) {
|
||||
const data = await categoriesRes.json();
|
||||
this.categories = data.categories || [];
|
||||
}
|
||||
this.templates = templatesData.templates || [];
|
||||
this.categories = categoriesData.categories || [];
|
||||
} catch (error) {
|
||||
console.error('Failed to load email templates:', error);
|
||||
this.showNotification('Failed to load templates', 'error');
|
||||
Utils.showToast('Failed to load templates', 'error');
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
@@ -101,20 +95,19 @@ function emailTemplatesPage() {
|
||||
|
||||
this.loadingTemplate = true;
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/v1/admin/email-templates/${this.editingTemplate.code}/${this.editLanguage}`
|
||||
const data = await apiClient.get(
|
||||
`/admin/email-templates/${this.editingTemplate.code}/${this.editLanguage}`
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
this.editForm = {
|
||||
subject: data.subject || '',
|
||||
body_html: data.body_html || '',
|
||||
body_text: data.body_text || '',
|
||||
variables: data.variables || [],
|
||||
required_variables: data.required_variables || []
|
||||
};
|
||||
} else if (response.status === 404) {
|
||||
this.editForm = {
|
||||
subject: data.subject || '',
|
||||
body_html: data.body_html || '',
|
||||
body_text: data.body_text || '',
|
||||
variables: data.variables || [],
|
||||
required_variables: data.required_variables || []
|
||||
};
|
||||
} catch (error) {
|
||||
if (error.status === 404) {
|
||||
// Template doesn't exist for this language yet
|
||||
this.editForm = {
|
||||
subject: '',
|
||||
@@ -123,11 +116,11 @@ function emailTemplatesPage() {
|
||||
variables: [],
|
||||
required_variables: []
|
||||
};
|
||||
this.showNotification(`No template for ${this.editLanguage.toUpperCase()} - create one by saving`, 'info');
|
||||
Utils.showToast(`No template for ${this.editLanguage.toUpperCase()} - create one by saving`, 'info');
|
||||
} else {
|
||||
console.error('Failed to load template:', error);
|
||||
Utils.showToast('Failed to load template', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load template:', error);
|
||||
this.showNotification('Failed to load template', 'error');
|
||||
} finally {
|
||||
this.loadingTemplate = false;
|
||||
}
|
||||
@@ -150,30 +143,21 @@ function emailTemplatesPage() {
|
||||
|
||||
this.saving = true;
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/v1/admin/email-templates/${this.editingTemplate.code}/${this.editLanguage}`,
|
||||
await apiClient.put(
|
||||
`/admin/email-templates/${this.editingTemplate.code}/${this.editLanguage}`,
|
||||
{
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
subject: this.editForm.subject,
|
||||
body_html: this.editForm.body_html,
|
||||
body_text: this.editForm.body_text
|
||||
})
|
||||
subject: this.editForm.subject,
|
||||
body_html: this.editForm.body_html,
|
||||
body_text: this.editForm.body_text
|
||||
}
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
this.showNotification('Template saved successfully', 'success');
|
||||
// Refresh templates list
|
||||
await this.loadData();
|
||||
} else {
|
||||
const error = await response.json();
|
||||
this.showNotification(error.detail || 'Failed to save template', 'error');
|
||||
}
|
||||
Utils.showToast('Template saved successfully', 'success');
|
||||
// Refresh templates list
|
||||
await this.loadData();
|
||||
} catch (error) {
|
||||
console.error('Failed to save template:', error);
|
||||
this.showNotification('Failed to save template', 'error');
|
||||
Utils.showToast(error.detail || 'Failed to save template', 'error');
|
||||
} finally {
|
||||
this.saving = false;
|
||||
}
|
||||
@@ -185,28 +169,20 @@ function emailTemplatesPage() {
|
||||
// Use sample variables for preview
|
||||
const sampleVariables = this.getSampleVariables(template.code);
|
||||
|
||||
const response = await fetch(
|
||||
`/api/v1/admin/email-templates/${template.code}/preview`,
|
||||
const data = await apiClient.post(
|
||||
`/admin/email-templates/${template.code}/preview`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
template_code: template.code,
|
||||
language: 'en',
|
||||
variables: sampleVariables
|
||||
})
|
||||
template_code: template.code,
|
||||
language: 'en',
|
||||
variables: sampleVariables
|
||||
}
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
this.previewData = await response.json();
|
||||
this.showPreviewModal = true;
|
||||
} else {
|
||||
this.showNotification('Failed to load preview', 'error');
|
||||
}
|
||||
this.previewData = data;
|
||||
this.showPreviewModal = true;
|
||||
} catch (error) {
|
||||
console.error('Failed to preview template:', error);
|
||||
this.showNotification('Failed to load preview', 'error');
|
||||
Utils.showToast('Failed to load preview', 'error');
|
||||
}
|
||||
},
|
||||
|
||||
@@ -257,47 +233,29 @@ function emailTemplatesPage() {
|
||||
|
||||
this.sendingTest = true;
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/v1/admin/email-templates/${this.editingTemplate.code}/test`,
|
||||
const result = await apiClient.post(
|
||||
`/admin/email-templates/${this.editingTemplate.code}/test`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
template_code: this.editingTemplate.code,
|
||||
language: this.editLanguage,
|
||||
to_email: this.testEmailAddress,
|
||||
variables: this.getSampleVariables(this.editingTemplate.code)
|
||||
})
|
||||
template_code: this.editingTemplate.code,
|
||||
language: this.editLanguage,
|
||||
to_email: this.testEmailAddress,
|
||||
variables: this.getSampleVariables(this.editingTemplate.code)
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
this.showNotification(`Test email sent to ${this.testEmailAddress}`, 'success');
|
||||
Utils.showToast(`Test email sent to ${this.testEmailAddress}`, 'success');
|
||||
this.showTestEmailModal = false;
|
||||
this.testEmailAddress = '';
|
||||
} else {
|
||||
this.showNotification(result.message || 'Failed to send test email', 'error');
|
||||
Utils.showToast(result.message || 'Failed to send test email', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to send test email:', error);
|
||||
this.showNotification('Failed to send test email', 'error');
|
||||
Utils.showToast('Failed to send test email', 'error');
|
||||
} finally {
|
||||
this.sendingTest = false;
|
||||
}
|
||||
},
|
||||
|
||||
// Notifications
|
||||
showNotification(message, type = 'info') {
|
||||
// Use global notification system if available
|
||||
if (window.showToast) {
|
||||
window.showToast(message, type);
|
||||
} else if (window.Alpine && Alpine.store('notifications')) {
|
||||
Alpine.store('notifications').add(message, type);
|
||||
} else {
|
||||
console.log(`[${type.toUpperCase()}] ${message}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user