@bytebrand/export-cars 1.22.29 → 1.22.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,3 @@
1
1
  export declare function convertToCSV(data: unknown): string;
2
2
  export declare const xmlStringReplacer: (str: string) => string;
3
+ export declare function parseCsvToObjects<T>(csv: string): T[];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.xmlStringReplacer = exports.convertToCSV = void 0;
3
+ exports.parseCsvToObjects = exports.xmlStringReplacer = exports.convertToCSV = void 0;
4
4
  const lodash_1 = require("lodash");
5
5
  function convertToCSV(data) {
6
6
  const converted = [];
@@ -16,4 +16,54 @@ const xmlStringReplacer = (str) => {
16
16
  return typeof str === 'string' ? str.replace(/&/g, '&amp;').replace(/[<>]/g, '') : '';
17
17
  };
18
18
  exports.xmlStringReplacer = xmlStringReplacer;
19
+ function parseCsvToObjects(csv) {
20
+ const rows = [];
21
+ let row = [];
22
+ let field = '';
23
+ let inQuotes = false;
24
+ for (let i = 0; i < csv.length; i += 1) {
25
+ const char = csv[i];
26
+ if (inQuotes) {
27
+ if (char === '"' && csv[i + 1] === '"') {
28
+ field += '"';
29
+ i += 1;
30
+ }
31
+ else if (char === '"') {
32
+ inQuotes = false;
33
+ }
34
+ else {
35
+ field += char;
36
+ }
37
+ }
38
+ else if (char === '"') {
39
+ inQuotes = true;
40
+ }
41
+ else if (char === ',') {
42
+ row.push(field);
43
+ field = '';
44
+ }
45
+ else if (char === '\n') {
46
+ row.push(field);
47
+ rows.push(row);
48
+ row = [];
49
+ field = '';
50
+ }
51
+ else if (char !== '\r') {
52
+ field += char;
53
+ }
54
+ }
55
+ if (field.length || row.length) {
56
+ row.push(field);
57
+ rows.push(row);
58
+ }
59
+ const [header, ...dataRows] = rows.filter(r => r.some(cell => cell.trim() !== ''));
60
+ if (!header) {
61
+ return [];
62
+ }
63
+ return dataRows.map(dataRow => header.reduce((acc, key, idx) => {
64
+ acc[key.trim()] = (dataRow[idx] ?? '').trim();
65
+ return acc;
66
+ }, {}));
67
+ }
68
+ exports.parseCsvToObjects = parseCsvToObjects;
19
69
  //# sourceMappingURL=converter.utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"converter.utils.js","sourceRoot":"","sources":["../../src/utils/converter.utils.ts"],"names":[],"mappings":";;;AAAA,mCAA6B;AAE7B,SAAgB,YAAY,CAAC,IAAa;IACxC,MAAM,SAAS,GAAG,EAAE,CAAC;IACrB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;QAC/B,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAa,CAAC;QAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;QAChE,IAAA,YAAG,EAAC,SAAS,EAAE,CAAC,EAAE,IAAI,QAAQ,GAAG,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IACH,OAAO,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AARD,oCAQC;AAEM,MAAM,iBAAiB,GAAG,CAAC,GAAW,EAAU,EAAE;IACvD,OAAO,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACxF,CAAC,CAAC;AAFW,QAAA,iBAAiB,qBAE5B"}
1
+ {"version":3,"file":"converter.utils.js","sourceRoot":"","sources":["../../src/utils/converter.utils.ts"],"names":[],"mappings":";;;AAAA,mCAA6B;AAE7B,SAAgB,YAAY,CAAC,IAAa;IACxC,MAAM,SAAS,GAAG,EAAE,CAAC;IACrB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;QAC/B,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAa,CAAC;QAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;QAChE,IAAA,YAAG,EAAC,SAAS,EAAE,CAAC,EAAE,IAAI,QAAQ,GAAG,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IACH,OAAO,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AARD,oCAQC;AAEM,MAAM,iBAAiB,GAAG,CAAC,GAAW,EAAU,EAAE;IACvD,OAAO,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACxF,CAAC,CAAC;AAFW,QAAA,iBAAiB,qBAE5B;AAIF,SAAgB,iBAAiB,CAAI,GAAW;IAC9C,MAAM,IAAI,GAAe,EAAE,CAAC;IAC5B,IAAI,GAAG,GAAa,EAAE,CAAC;IACvB,IAAI,KAAK,GAAG,EAAE,CAAC;IACf,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE;QACtC,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,QAAQ,EAAE;YACZ,IAAI,IAAI,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE;gBACtC,KAAK,IAAI,GAAG,CAAC;gBACb,CAAC,IAAI,CAAC,CAAC;aACR;iBAAM,IAAI,IAAI,KAAK,GAAG,EAAE;gBACvB,QAAQ,GAAG,KAAK,CAAC;aAClB;iBAAM;gBACL,KAAK,IAAI,IAAI,CAAC;aACf;SACF;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE;YACvB,QAAQ,GAAG,IAAI,CAAC;SACjB;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE;YACvB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChB,KAAK,GAAG,EAAE,CAAC;SACZ;aAAM,IAAI,IAAI,KAAK,IAAI,EAAE;YACxB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACf,GAAG,GAAG,EAAE,CAAC;YACT,KAAK,GAAG,EAAE,CAAC;SACZ;aAAM,IAAI,IAAI,KAAK,IAAI,EAAE;YACxB,KAAK,IAAI,IAAI,CAAC;SACf;KACF;IACD,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE;QAC9B,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;KAChB;IAED,MAAM,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IACnF,IAAI,CAAC,MAAM,EAAE;QACX,OAAO,EAAE,CAAC;KACX;IAED,OAAO,QAAQ,CAAC,GAAG,CACjB,OAAO,CAAC,EAAE,CACR,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAC9B,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9C,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,EAA4B,CAAM,CACxC,CAAC;AACJ,CAAC;AAhDD,8CAgDC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytebrand/export-cars",
3
- "version": "1.22.29",
3
+ "version": "1.22.31",
4
4
  "description": "",
5
5
  "author": "bytebrand",
6
6
  "license": "UNLICENSED",
@@ -33,7 +33,7 @@ export class Config {
33
33
  mappingSpreadsheetTitle: string;
34
34
  dealersSpreadsheetId: string;
35
35
  dealersSpreadsheetTitle: string;
36
- metaPushPrioritySpreadsheetId: string;
36
+ metaPushPriorityCsvUrl: string;
37
37
 
38
38
  protected environmentConfig = {
39
39
  [Environment.DEVELOP]: {
@@ -66,7 +66,7 @@ export class Config {
66
66
  this.mappingSpreadsheetId = '147qz9sTgs1wi13ua8YKa0IgfxAn1X_qH6LkGnAnzeyY';
67
67
  this.dealersSpreadsheetId = '1gWrcA-uRTpna1h66Mbe2Y7NA0tIhlUaQXBcS4a_UzOw';
68
68
  this.dealersSpreadsheetTitle = 'dealers_mapping';
69
- this.metaPushPrioritySpreadsheetId = params.metaPushPrioritySpreadsheetId;
69
+ this.metaPushPriorityCsvUrl = params.metaPushPriorityCsvUrl;
70
70
  this.userActionsUrl = `https://www.${this.domain}/service/user-actions`;
71
71
  this.imboUrl = `https://www.${this.domain}/service/image-imbo`;
72
72
  this.imageUrl = `https://images.${this.domain}`;
@@ -6,4 +6,4 @@ export const DEFAULT_CITY = 'Sandersdorf-Brehna';
6
6
  export const DEFAULT_ADDR1 = 'Max-Planck-Str. 19';
7
7
  export const TIMESTAMP_FIRST_YEAR = 1970;
8
8
  export const META_PUSH_PRIORITY_STANDARD = 'standard';
9
- export const META_PUSH_PRIORITY_ALLOWED_VALUES = ['user_priority_1', 'user_priority_2'];
9
+ export const META_PUSH_PRIORITY_ALLOWED_VALUES = ['dealer_priority_1', 'dealer_priority_2'];
@@ -7,7 +7,7 @@ export interface DealersMapping {
7
7
  }
8
8
 
9
9
  export interface MetaPushPriorityMapping {
10
- user_id: string;
10
+ dealer_id: string;
11
11
  meta_push_priority: string;
12
12
  comment?: string;
13
13
  }
@@ -10,5 +10,5 @@ export interface Params {
10
10
  isNewCar?: boolean;
11
11
  cpc?: string;
12
12
  ownerId?: string;
13
- metaPushPrioritySpreadsheetId?: string;
13
+ metaPushPriorityCsvUrl?: string;
14
14
  }
@@ -1,8 +1,10 @@
1
1
  import { Injectable } from '@nestjs/common';
2
+ import axios from 'axios';
2
3
  import { MappingRules } from '../interfaces/mapping-rules.interface';
3
4
  import { GoogleSpreadsheet, GoogleSpreadsheetRow } from 'google-spreadsheet';
4
5
  import { ConfigService } from './config.service';
5
6
  import { DealersMapping, MetaPushPriorityMapping } from '../interfaces/dealers-mapping.interface';
7
+ import { parseCsvToObjects } from '../utils';
6
8
 
7
9
  @Injectable()
8
10
  export class MappingService {
@@ -44,21 +46,19 @@ export class MappingService {
44
46
 
45
47
  async getMetaPushPriorityMapping(): Promise<MetaPushPriorityMapping[]> {
46
48
  if (!this.metaPushPriorities) {
47
- const spreadsheetId = this.configService.config.metaPushPrioritySpreadsheetId;
48
- if (!spreadsheetId) {
49
+ const csvUrl = this.configService.config.metaPushPriorityCsvUrl;
50
+ if (!csvUrl) {
49
51
  this.metaPushPriorities = [];
50
52
  return this.metaPushPriorities;
51
53
  }
52
- const spreadsheet = new GoogleSpreadsheet(spreadsheetId);
53
- spreadsheet.useApiKey(this.configService.config.apikey);
54
- await spreadsheet.loadInfo();
55
- const rows = await spreadsheet.sheetsByIndex[0].getRows();
56
- this.metaPushPriorities = this.rowsToRules(rows) as MetaPushPriorityMapping[];
54
+ // "Publish to the web" CSV export — a plain public GET, no Google API key/quota involved.
55
+ const { data } = await axios.get<string>(csvUrl, { responseType: 'text' });
56
+ this.metaPushPriorities = parseCsvToObjects<MetaPushPriorityMapping>(data);
57
57
  }
58
58
  return this.metaPushPriorities;
59
59
  }
60
60
 
61
- private rowsToRules(rows: GoogleSpreadsheetRow[]): MappingRules[] | DealersMapping[] | MetaPushPriorityMapping[] {
61
+ private rowsToRules(rows: GoogleSpreadsheetRow[]): MappingRules[] | DealersMapping[] {
62
62
  return rows.map(row =>
63
63
  Object.assign(
64
64
  {},
@@ -166,7 +166,7 @@ export class FbTransformer {
166
166
 
167
167
  private async getMetaPushPriority(ownerId: string): Promise<string> {
168
168
  const priorities = await this.mappingService.getMetaPushPriorityMapping();
169
- const entry = priorities.find(priority => priority.user_id === ownerId);
169
+ const entry = priorities.find(priority => priority.dealer_id === ownerId);
170
170
  const value = get(entry, 'meta_push_priority', '');
171
171
  return includes(META_PUSH_PRIORITY_ALLOWED_VALUES, value) ? value : META_PUSH_PRIORITY_STANDARD;
172
172
  }
@@ -13,3 +13,55 @@ export function convertToCSV(data: unknown): string {
13
13
  export const xmlStringReplacer = (str: string): string => {
14
14
  return typeof str === 'string' ? str.replace(/&/g, '&amp;').replace(/[<>]/g, '') : '';
15
15
  };
16
+
17
+ // Parses a "Publish to web" Google Sheets CSV export (RFC4180-ish, quoted fields may
18
+ // contain commas/newlines) into row arrays, then maps rows to objects keyed by header.
19
+ export function parseCsvToObjects<T>(csv: string): T[] {
20
+ const rows: string[][] = [];
21
+ let row: string[] = [];
22
+ let field = '';
23
+ let inQuotes = false;
24
+
25
+ for (let i = 0; i < csv.length; i += 1) {
26
+ const char = csv[i];
27
+ if (inQuotes) {
28
+ if (char === '"' && csv[i + 1] === '"') {
29
+ field += '"';
30
+ i += 1;
31
+ } else if (char === '"') {
32
+ inQuotes = false;
33
+ } else {
34
+ field += char;
35
+ }
36
+ } else if (char === '"') {
37
+ inQuotes = true;
38
+ } else if (char === ',') {
39
+ row.push(field);
40
+ field = '';
41
+ } else if (char === '\n') {
42
+ row.push(field);
43
+ rows.push(row);
44
+ row = [];
45
+ field = '';
46
+ } else if (char !== '\r') {
47
+ field += char;
48
+ }
49
+ }
50
+ if (field.length || row.length) {
51
+ row.push(field);
52
+ rows.push(row);
53
+ }
54
+
55
+ const [header, ...dataRows] = rows.filter(r => r.some(cell => cell.trim() !== ''));
56
+ if (!header) {
57
+ return [];
58
+ }
59
+
60
+ return dataRows.map(
61
+ dataRow =>
62
+ header.reduce((acc, key, idx) => {
63
+ acc[key.trim()] = (dataRow[idx] ?? '').trim();
64
+ return acc;
65
+ }, {} as Record<string, string>) as T,
66
+ );
67
+ }