openvibers/openvibe.coupons Commits
Public coupon events carry only a short reason code: a staff note or a calling service's free-text reason became the public lifecycle event's reason; anything that is not a code is 'other' (staff notes 'staff'), and report events drop a free-text reason
Changes
@@@ -1,5 +1,12 @@'use strict';++/** A reason in a public event is a short code; a staff note or a calling service's free text never leaves Coupons. */++function publicReason(reason) {++ const r = String(reason || '');++ if (r.startsWith('staff:')) return 'staff';++ return /^[a-z][a-z0-9_]{0,39}$/.test(r) ? r : 'other';++}++/*** Codes: submission, restrictions, hints, evidence, status and confidence, expiry.*@@@ -265,7 +272,7 @@ function createCoupons({ store, merchants, publication }) {if (statusChanged || confChanged) q.history.run(id, before.status, after.status, before.confidence, after.confidence, reason, actor, now);if (statusChanged) {const type = after.status === 'expired' ? 'coupons.coupon.expired' : after.status === 'disabled' ? 'coupons.coupon.disabled' : 'coupons.coupon.updated';-- publication.emit(type, { type: 'coupon', id }, lifecyclePayload(after, { previous_status: before.status, reason: reason.startsWith('staff:') ? 'staff' : reason }), { isPublic: publiclyListed(after) || publiclyListed(before), traceparent });++ publication.emit(type, { type: 'coupon', id }, lifecyclePayload(after, { previous_status: before.status, reason: publicReason(reason) }), { isPublic: publiclyListed(after) || publiclyListed(before), traceparent });}if (confChanged) {publication.emit('coupons.confidence.changed', { type: 'coupon', id }, { merchant_id: after.merchant_id, from: before.confidence, to: after.confidence, status: after.status }, { traceparent });@@@ -89,7 +89,7 @@ function createReports({ store, config, coupons, merchants, publication }) {throw new ApiError(429, 'report.rate_limited', 'too many reports; try again later');}q.insert.run({ coupon_id: c.id, reporter_key: key, channel: who.channel, install_id: who.install, day, outcome, reason, now });-- publication.emit('coupons.report.created', { type: 'coupon', id: c.id }, { merchant_id: c.merchant_id, outcome, ...(reason ? { reason } : {}), channel: who.channel, day }, { traceparent });++ publication.emit('coupons.report.created', { type: 'coupon', id: c.id }, { merchant_id: c.merchant_id, outcome, ...(reason && /^[a-z][a-z0-9_]{0,39}$/.test(reason) ? { reason } : {}), channel: who.channel, day }, { traceparent });} else {q.correct.run({ id: existing.id, outcome, reason, channel: who.channel, install_id: who.install, now });}
@@ -1,5 +1,12 @@
@@ -1,5 +1,12 @@
'use strict';
'use strict';
+/** A reason in a public event is a short code; a staff note or a calling service's free text never leaves Coupons. */
+function publicReason(reason) {
+ const r = String(reason || '');
+ if (r.startsWith('staff:')) return 'staff';
+ return /^[a-z][a-z0-9_]{0,39}$/.test(r) ? r : 'other';
+}
+
/**
/**
* Codes: submission, restrictions, hints, evidence, status and confidence, expiry.
* Codes: submission, restrictions, hints, evidence, status and confidence, expiry.
*
*
@@ -265,7 +272,7 @@ function createCoupons({ store, merchants, publication }) {
@@ -265,7 +272,7 @@ function createCoupons({ store, merchants, publication }) {
if (statusChanged || confChanged) q.history.run(id, before.status, after.status, before.confidence, after.confidence, reason, actor, now);
if (statusChanged || confChanged) q.history.run(id, before.status, after.status, before.confidence, after.confidence, reason, actor, now);
if (statusChanged) {
if (statusChanged) {
const type = after.status === 'expired' ? 'coupons.coupon.expired' : after.status === 'disabled' ? 'coupons.coupon.disabled' : 'coupons.coupon.updated';
const type = after.status === 'expired' ? 'coupons.coupon.expired' : after.status === 'disabled' ? 'coupons.coupon.disabled' : 'coupons.coupon.updated';
- publication.emit(type, { type: 'coupon', id }, lifecyclePayload(after, { previous_status: before.status, reason: reason.startsWith('staff:') ? 'staff' : reason }), { isPublic: publiclyListed(after) || publiclyListed(before), traceparent });
+ publication.emit(type, { type: 'coupon', id }, lifecyclePayload(after, { previous_status: before.status, reason: publicReason(reason) }), { isPublic: publiclyListed(after) || publiclyListed(before), traceparent });
}
}
if (confChanged) {
if (confChanged) {
publication.emit('coupons.confidence.changed', { type: 'coupon', id }, { merchant_id: after.merchant_id, from: before.confidence, to: after.confidence, status: after.status }, { traceparent });
publication.emit('coupons.confidence.changed', { type: 'coupon', id }, { merchant_id: after.merchant_id, from: before.confidence, to: after.confidence, status: after.status }, { traceparent });
@@ -89,7 +89,7 @@ function createReports({ store, config, coupons, merchants, publication }) {
@@ -89,7 +89,7 @@ function createReports({ store, config, coupons, merchants, publication }) {
throw new ApiError(429, 'report.rate_limited', 'too many reports; try again later');
throw new ApiError(429, 'report.rate_limited', 'too many reports; try again later');
}
}
q.insert.run({ coupon_id: c.id, reporter_key: key, channel: who.channel, install_id: who.install, day, outcome, reason, now });
q.insert.run({ coupon_id: c.id, reporter_key: key, channel: who.channel, install_id: who.install, day, outcome, reason, now });
- publication.emit('coupons.report.created', { type: 'coupon', id: c.id }, { merchant_id: c.merchant_id, outcome, ...(reason ? { reason } : {}), channel: who.channel, day }, { traceparent });
+ publication.emit('coupons.report.created', { type: 'coupon', id: c.id }, { merchant_id: c.merchant_id, outcome, ...(reason && /^[a-z][a-z0-9_]{0,39}$/.test(reason) ? { reason } : {}), channel: who.channel, day }, { traceparent });
} else {
} else {
q.correct.run({ id: existing.id, outcome, reason, channel: who.channel, install_id: who.install, now });
q.correct.run({ id: existing.id, outcome, reason, channel: who.channel, install_id: who.install, now });
}
}