diff --git a/test/api/unit/libs/xmlMarshaller.test.js b/test/api/unit/libs/xmlMarshaller.test.js
index 73633a4c30..a1d201df29 100644
--- a/test/api/unit/libs/xmlMarshaller.test.js
+++ b/test/api/unit/libs/xmlMarshaller.test.js
@@ -42,3 +42,109 @@ describe('xml marshaller marshalls user data', () => {
`);
});
});
+
+describe('xml marshaller marshalls user data (with purchases)', () => {
+ const minimumUser = {
+ pinnedItems: [],
+ unpinnedItems: [],
+ inbox: {},
+ };
+
+ function userDataWith (fields) {
+ return { ...minimumUser, ...fields };
+ }
+
+ it('maps the purchases field with data that begins with a number', () => {
+ const userData = userDataWith({
+ purchased: {
+ ads: false,
+ txnCount: 0,
+ skin: {
+ eb052b: true,
+ '0ff591': true,
+ '2b43f6': true,
+ d7a9f7: true,
+ '800ed0': true,
+ rainbow: true,
+ },
+ },
+ });
+
+ const xml = xmlMarshaller.marshallUserData(userData);
+
+ expect(xml).to.equal(`
+
+
+ false
+ 0
+ eb052b
+ 0ff591
+ 2b43f6
+ d7a9f7
+ 800ed0
+ rainbow
+
+`);
+ });
+});
+
+describe('xml marshaller marshalls user data (with purchases nested)', () => {
+ const minimumUser = {
+ pinnedItems: [],
+ unpinnedItems: [],
+ inbox: {},
+ };
+
+ function userDataWith (fields) {
+ return { ...minimumUser, ...fields };
+ }
+
+ it('maps the purchases field with data that begins with a number and nested objects', () => {
+ const userData = userDataWith({
+ purchased: {
+ ads: false,
+ txnCount: 0,
+ skin: {
+ eb052b: true,
+ '0ff591': true,
+ '2b43f6': true,
+ d7a9f7: true,
+ '800ed0': true,
+ rainbow: true,
+ },
+ plan: {
+ consecutive: {
+ count: 0,
+ offset: 0,
+ gemCapExtra: 0,
+ trinkets: 0,
+ },
+ },
+ },
+ });
+
+ const xml = xmlMarshaller.marshallUserData(userData);
+
+ expect(xml).to.equal(`
+
+
+ false
+ 0
+ eb052b
+ 0ff591
+ 2b43f6
+ d7a9f7
+ 800ed0
+ rainbow
+
+ -
+ 0
+ 0
+ 0
+ 0
+
+
+
+`);
+ });
+});
diff --git a/website/server/libs/xmlMarshaller.js b/website/server/libs/xmlMarshaller.js
index e2a4b14c40..c1cbbd1788 100644
--- a/website/server/libs/xmlMarshaller.js
+++ b/website/server/libs/xmlMarshaller.js
@@ -23,7 +23,33 @@ export function marshallUserData (userData) {
type: i.type,
}));
- return js2xml.parse('user', userData, {
+ const copyUserData = JSON.parse(JSON.stringify(userData));
+
+ const newPurchased = {};
+ if (userData.purchased != null) {
+ for (const itemType in userData.purchased) {
+ if (userData.purchased[itemType] != null) {
+ if (typeof userData.purchased[itemType] === 'object') {
+ const fixedData = [];
+ for (const item in userData.purchased[itemType]) {
+ if (item != null) {
+ if (typeof userData.purchased[itemType][item] === 'object') {
+ fixedData.push({ item: userData.purchased[itemType][item] });
+ } else {
+ fixedData.push(item);
+ }
+ }
+ }
+ newPurchased[itemType] = fixedData;
+ } else {
+ newPurchased[itemType] = userData.purchased[itemType];
+ }
+ }
+ }
+ copyUserData.purchased = newPurchased;
+ }
+
+ return js2xml.parse('user', copyUserData, {
cdataInvalidChars: true,
replaceInvalidChars: true,
declaration: {