- Correctie reset password en confirm email adress by adapting the prefixed_url_for to use config setting

- Adaptation of DPA and T&Cs
- Refer to privacy statement as DPA, not a privacy statement
- Startup of enforcing signed DPA and T&Cs
- Adaptation of eveai_chat_client to ensure we retrieve correct DPA & T&Cs
This commit is contained in:
Josako
2025-10-13 14:28:09 +02:00
parent 83272a4e2a
commit 37819cd7e5
35 changed files with 5350 additions and 241 deletions

View File

@@ -110,7 +110,7 @@ export function useContentModal() {
throw new Error(data.error || 'Onbekende fout bij het laden van content');
}
} else if (data.content !== undefined) {
// Legacy format without success property (current privacy/terms endpoints)
// Legacy format without success property (current dpa/terms endpoints)
modalState.content = data.content || '';
modalState.version = data.version || '';
} else if (data.error) {

View File

@@ -24,19 +24,19 @@ export default {
props: {
template: { type: String, required: true },
asButton: { type: Boolean, default: false },
ariaPrivacy: { type: String, default: 'Open privacy statement in a dialog' },
ariaTerms: { type: String, default: 'Open terms and conditions in a dialog' }
ariaPrivacy: { type: String, default: 'Open Data Privacy Agreement in a dialog' },
ariaTerms: { type: String, default: 'Open Terms and Conditions in a dialog' }
},
emits: ['open-privacy', 'open-terms'],
emits: ['open-dpa', 'open-terms'],
computed: {
linkTag() {
return this.asButton ? 'button' : 'a';
},
nodes() {
// Parse only allowed tags <privacy>...</privacy> and <terms>...</terms>
// Parse only allowed tags <dpa>...</dpa> and <terms>...</terms>
const source = (this.template || '');
// 2) parse only allowed tags <privacy>...</privacy> and <terms>...</terms>
// 2) parse only allowed tags <dpa>...</dpa> and <terms>...</terms>
const pattern = /<(privacy|terms)>([\s\S]*?)<\/\1>/gi;
const out = [];
let lastIndex = 0;
@@ -48,9 +48,9 @@ export default {
out.push({ type: 'text', text: source.slice(lastIndex, start) });
}
out.push({
type: tag, // 'privacy' | 'terms'
type: tag, // 'dpa' | 'terms'
label: (label || '').trim(),
aria: tag === 'privacy' ? this.ariaPrivacy : this.ariaTerms
aria: tag === 'dpa' ? this.ariaPrivacy : this.ariaTerms
});
lastIndex = start + full.length;
}
@@ -62,7 +62,7 @@ export default {
},
methods: {
emitClick(kind) {
if (kind === 'privacy') this.$emit('open-privacy');
if (kind === 'dpa') this.$emit('open-dpa');
if (kind === 'terms') this.$emit('open-terms');
}
}

View File

@@ -480,7 +480,7 @@ export default {
// Modal handling methods
openPrivacyModal() {
this.loadContent('privacy');
this.loadContent('dpa');
},
openTermsModal() {
@@ -494,15 +494,15 @@ export default {
retryLoad() {
// Retry loading the last requested content type
const currentTitle = this.contentModal.modalState.title.toLowerCase();
if (currentTitle.includes('privacy')) {
this.loadContent('privacy');
if (currentTitle.includes('dpa')) {
this.loadContent('dpa');
} else if (currentTitle.includes('terms')) {
this.loadContent('terms');
}
},
async loadContent(contentType) {
const title = contentType === 'privacy' ? 'Privacy Statement' : 'Terms & Conditions';
const title = contentType === 'dpa' ? 'Data Privacy Agreement' : 'Terms & Conditions';
const contentUrl = `${this.apiPrefix}/${contentType}`;
// Use the composable to show modal and load content

View File

@@ -104,12 +104,12 @@
>
<!-- Regular checkbox label -->
<span v-if="!isConsentField" class="checkbox-text">{{ field.name }}</span>
<!-- Consent field with privacy and terms links (rich, multilingual) -->
<!-- Consent field with dpa and terms links (rich, multilingual) -->
<ConsentRichText
v-else
class="checkbox-text consent-text"
:template="texts.consentRich"
:aria-privacy="texts.ariaPrivacy || 'Open privacy statement in a dialog'"
:aria-privacy="texts.ariaPrivacy || 'Open dpa statement in a dialog'"
:aria-terms="texts.ariaTerms || 'Open terms and conditions in a dialog'"
@open-privacy="openPrivacyModal"
@open-terms="openTermsModal"
@@ -203,12 +203,12 @@ export default {
default: null
}
},
emits: ['update:modelValue', 'open-privacy-modal', 'open-terms-modal', 'keydown-enter'],
emits: ['update:modelValue', 'open-dpa-modal', 'open-terms-modal', 'keydown-enter'],
setup() {
// Consent text constants (English base) - rich template
const consentTexts = {
consentRich: "I agree with the <privacy>privacy statement</privacy> and the <terms>terms and conditions</terms>",
ariaPrivacy: 'Open privacy statement in a dialog',
consentRich: "I agree with the <dpa>dpa statement</dpa> and the <terms>terms and conditions</terms>",
ariaPrivacy: 'Open dpa statement in a dialog',
ariaTerms: 'Open terms and conditions in a dialog'
};
@@ -259,8 +259,8 @@ export default {
// 4) Ultimate fallback (should not happen): provide a safe default
return {
consentRich: "I agree with the <privacy>privacy statement</privacy> and the <terms>terms and conditions</terms>",
ariaPrivacy: 'Open privacy statement in a dialog',
consentRich: "I agree with the <dpa>dpa statement</dpa> and the <terms>terms and conditions</terms>",
ariaPrivacy: 'Open dpa statement in a dialog',
ariaTerms: 'Open terms and conditions in a dialog'
};
},
@@ -332,7 +332,7 @@ export default {
}
},
openPrivacyModal() {
this.$emit('open-privacy-modal');
this.$emit('open-dpa-modal');
},
openTermsModal() {
this.$emit('open-terms-modal');

View File

@@ -387,35 +387,35 @@ def translate():
@chat_bp.route('/privacy', methods=['GET'])
def privacy_statement():
"""
Public AJAX endpoint for privacy statement content
Public AJAX endpoint for dpa statement content
Returns JSON response suitable for modal display
"""
try:
# Use content_manager to get the latest privacy content
content_data = content_manager.read_content('privacy')
# Use content_manager to get the latest dpa content
content_data = content_manager.read_content('dpa')
if not content_data:
current_app.logger.error("Privacy statement content not found")
current_app.logger.error("Data Privacy Agreement content not found")
return jsonify({
'error': 'Privacy statement not available',
'message': 'The privacy statement could not be loaded at this time.'
'error': 'Data Privacy Agreement not available',
'message': 'The Data Pdpa Agreement could not be loaded at this time.'
}), 404
current_app.logger.debug(f"Content data: {content_data}")
# Return JSON response for AJAX consumption
return jsonify({
'title': 'Privacy Statement',
'title': 'Data Privacy Agreement',
'content': content_data['content'],
'version': content_data['version'],
'content_type': content_data['content_type']
}), 200
except Exception as e:
current_app.logger.error(f"Error loading privacy statement: {str(e)}")
current_app.logger.error(f"Error loading Data Privacy Agreement: {str(e)}")
return jsonify({
'error': 'Server error',
'message': 'An error occurred while loading the privacy statement.'
'message': 'An error occurred while loading the Data Privacy Agreement.'
}), 500