@sebbo2002/tgtg-ical 3.0.9 → 3.1.0-develop.2
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.
- package/dist/chunk-2ETYXYMT.js +60 -0
- package/dist/chunk-2ETYXYMT.js.map +1 -0
- package/dist/cleanup.js +1 -1
- package/dist/inhale-mail.js +1 -1
- package/dist/start.js +2 -2
- package/dist/start.js.map +1 -1
- package/package.json +11 -10
- package/src/prisma/prisma/browser.ts +39 -0
- package/src/prisma/prisma/client.ts +61 -0
- package/src/prisma/prisma/commonInputTypes.ts +384 -0
- package/src/prisma/prisma/enums.ts +15 -0
- package/src/prisma/prisma/internal/class.ts +220 -0
- package/src/prisma/prisma/internal/prismaNamespace.ts +1016 -0
- package/src/prisma/prisma/internal/prismaNamespaceBrowser.ts +183 -0
- package/src/prisma/prisma/models/Event.ts +1669 -0
- package/src/prisma/prisma/models/Location.ts +1336 -0
- package/src/prisma/prisma/models/Mail.ts +1090 -0
- package/src/prisma/prisma/models/User.ts +1192 -0
- package/src/prisma/prisma/models.ts +15 -0
- package/src/prisma/schema.prisma +38 -37
- package/dist/chunk-5TQHQ2B4.js +0 -2
- package/dist/chunk-5TQHQ2B4.js.map +0 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
|
3
|
+
/* eslint-disable */
|
|
4
|
+
// biome-ignore-all lint: generated file
|
|
5
|
+
// @ts-nocheck
|
|
6
|
+
/*
|
|
7
|
+
* This is a barrel export file for all models and their related types.
|
|
8
|
+
*
|
|
9
|
+
* 🟢 You can import this file directly.
|
|
10
|
+
*/
|
|
11
|
+
export type * from './models/User.js'
|
|
12
|
+
export type * from './models/Event.js'
|
|
13
|
+
export type * from './models/Location.js'
|
|
14
|
+
export type * from './models/Mail.js'
|
|
15
|
+
export type * from './commonInputTypes.js'
|
package/src/prisma/schema.prisma
CHANGED
|
@@ -2,56 +2,57 @@
|
|
|
2
2
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
3
3
|
|
|
4
4
|
generator client {
|
|
5
|
-
|
|
5
|
+
provider = "prisma-client"
|
|
6
|
+
output = "./prisma"
|
|
7
|
+
importFileExtension = "js"
|
|
6
8
|
}
|
|
7
9
|
|
|
8
10
|
datasource db {
|
|
9
|
-
|
|
10
|
-
url = env("DATABASE_URL")
|
|
11
|
+
provider = "mysql"
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
model User {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
id String @id @default(uuid())
|
|
16
|
+
prefix String @unique
|
|
17
|
+
createdAt DateTime @default(now())
|
|
18
|
+
lastSeenAt DateTime @default(now())
|
|
19
|
+
event Event[]
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
model Event {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
id String @id @default(uuid())
|
|
24
|
+
orderId String @unique
|
|
25
|
+
from DateTime
|
|
26
|
+
to DateTime
|
|
27
|
+
amount Int
|
|
28
|
+
price Int
|
|
29
|
+
user User @relation(fields: [userId], references: [id])
|
|
30
|
+
userId String
|
|
31
|
+
location Location @relation(fields: [locationId], references: [id])
|
|
32
|
+
locationId String
|
|
33
|
+
createdAt DateTime @default(now())
|
|
34
|
+
orderedAt DateTime
|
|
35
|
+
invoicedAt DateTime?
|
|
36
|
+
canceledAt DateTime?
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
model Location {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
id String @id @default(uuid())
|
|
41
|
+
name String
|
|
42
|
+
address String
|
|
43
|
+
latitude Float?
|
|
44
|
+
longitude Float?
|
|
45
|
+
emoji String? @db.VarChar(16)
|
|
46
|
+
createdAt DateTime @default(now())
|
|
47
|
+
event Event[]
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
model Mail {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
id String @id @default(uuid())
|
|
52
|
+
raw String @db.MediumText
|
|
53
|
+
error String? @db.MediumText
|
|
54
|
+
errorId String?
|
|
55
|
+
version String?
|
|
56
|
+
createdAt DateTime @default(now())
|
|
57
|
+
erroredAt DateTime?
|
|
57
58
|
}
|
package/dist/chunk-5TQHQ2B4.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{init as I}from"@sentry/node";import{readFileSync as A}from"fs";import{dirname as k,resolve as g}from"path";import{fileURLToPath as x}from"url";I({dsn:process.env.SENTRY_DSN||"https://5e4630d58e5f4c778ce22140c53b3684@glitch.sebbo.net/9"});var u=k(x(import.meta.url));u.endsWith("/dist")?u=g(u,"..","src"):u=g(u,"..");function v(l){return g(u,l||"")}var D;try{D=JSON.parse(A(v("../package.json"),"utf8")).version}catch(l){console.log("Failed getting tgtg-ical version:"),console.error(l)}var c={baseMail:process.env.BASE_MAIL||"@tgtg-ical.sebbo.net",baseUrl:process.env.BASE_URL||"https://tgtg-ical.sebbo.net",src:v,version:D};import{PrismaClient as P}from"@prisma/client";var z=new P,i=z;import{captureException as B}from"@sentry/node";import E from"he";import{simpleParser as T}from"mailparser";import n from"moment-timezone";var b={"\u{1F32D}":[/Ikea/],"\u{1F32E}":[/Enchilada/,/Besitos/],"\u{1F354}":[/Burger/,/McDonald[‘|']?s/,/Burger King/,/Hans im Glück/,/Peter Pane/],"\u{1F355}":[/Domino‘s/,/Pizza Hut/,/L[‘|']Osteria/,/Call a Pizza/,/Smiley[‘|']s Pizza/],"\u{1F357}":[/KFC/],"\u{1F35D}":[/LaTagliatella/,/Vapiano/],"\u{1F364}":[/Nordsee/],"\u{1F369}":[/Donut/,/Dunkin/],"\u{1F36A}":[/Starbucks/],"\u{1F950}":[/LeCroBag/],"\u{1F956}":[/Bäckerei/,/Back/,/BackWerk/,/Kamps/,/Kamps Backstuben/,/Junge Die Bäckerei/,/Back-Factory/],"\u{1F957}":[/dean ?& ?david/],"\u{1F968}":[/Brezel/,/Ditsch/],"\u{1F969}":[/Steakhouse/,/Block House/,/Jim Block/],"\u{1F96A}":[/Sandwich/,/Tank ?& ?Rast/,/T&R Raststätten/,/Autohöfe/,/Aral/,/Shell/,/Jet Tank/,/Subway/,/Caf[é|e] bonjour/,/Total Deutschland/,/Esso:? Snack ?& ?Shop/],"\u{1F6D2}":[/Edeka/,/Netto/,/Rewe/,/Penny/,/Lidl/,/Kaufland/,/Aldi/,/dm/,/Rossmann/,/Globus/,/Metro/,/Norma/,/Tegut/]};function w(l){for(let t in b)if(!!b[t].map(a=>new RegExp(a,"i")).find(a=>a.test(l)))return t;return null}var M=class{static async geocode(t){let r=await fetch("https://nominatim.openstreetmap.org/search?format=json&limit=1&q="+encodeURIComponent(t),{headers:{Referer:c.baseUrl,"User-Agent":`tgtg-ical/${c.version} (${c.baseUrl})`}});if(!r.ok)throw new Error("Geocoding failed: "+r.statusText);await new Promise(a=>setTimeout(a,1e3));let e=await r.json();return!Array.isArray(e)||e.length===0?{latitude:null,longitude:null}:{latitude:parseFloat(e[0].lat),longitude:parseFloat(e[0].lon)}}static async handleMail(t){try{let r=await this.parseMail(t.raw);r&&await this.applyParsedMail(r),await i.mail.delete({where:{id:t.id}})}catch(r){let e=B(r);await i.mail.update({data:{error:r instanceof Error?r.stack:String(r),erroredAt:new Date,errorId:e,version:c.version},where:{id:t.id}})}}static async inhaleMail(t){let r=await i.mail.create({data:{raw:t}});await this.handleMail(r)}static async parseMail(t,r=c.baseMail){let e=await T(t,{skipHtmlToText:!0,skipImageLinks:!0,skipTextLinks:!0,skipTextToHtml:!0});if(!e.from?.value[0].address?.endsWith("toogoodtogo.com"))throw new Error("Not a TGTG email!");let a=(Array.isArray(e.to)?e.to:[e.to]).map(o=>o?.value).flat().filter(o=>!!o).map(o=>o.address).find(o=>o?.endsWith(r));if(!a){let o=e.headers.get("received"),d=new RegExp(`([\\w-]+${c.baseMail})`,"i");Array.isArray(o)&&o.forEach(s=>{let m=(typeof s=="string"?s:s.value).match(d);m&&(a=m[1])})}if(!a)throw new Error("No recipient found!");if(e.headers.get("x-pm-tag")==="consumer_order_confirm"){let o=this.parseOrderMail(e);return{to:a,...o}}if(e.headers.get("x-pm-tag")==="collection_time_changed"){let o=this.parseChangeMail(e);return{to:a,...o}}if(e.headers.get("x-pm-tag")==="consumer_order_reverted"){let o=this.parseCancellationMail(e);if(o)return{to:a,...o}}if(e.headers.get("x-pm-tag")==="invoice"){let o=this.parseInvoiceMail(e);if(o)return{to:a,...o}}if(!(!e.headers.get("x-pm-tag")&&!e.headers.get("x-pm-message-id")))throw e.headers.get("x-pm-tag")?new Error(`Unsupported email type: ${e.headers.get("x-pm-tag")}`):new Error("Not implemented!")}static async runCleanup(){let t=await i.mail.findMany({orderBy:{erroredAt:"asc"},take:10,where:{OR:[{error:null},{version:null},{version:{not:c.version}}]}});for(let r of t)await this.handleMail(r);await i.user.deleteMany({where:{OR:[{lastSeenAt:{lt:n().subtract(8,"weeks").toDate()}},{createdAt:{lt:n().subtract(3,"hours").toDate()},lastSeenAt:{equals:i.user.fields.createdAt}}]}}),await i.event.deleteMany({where:{to:{lt:n().subtract(4,"weeks").toDate()}}}),await i.mail.deleteMany({where:{createdAt:{lt:n().subtract(2,"weeks").toDate()}}})}static async applyParsedMail(t){let r=await this.findUser(t.to);if(t.type==="order"){let e=await this.getLocation(t.location);await i.event.upsert({create:{amount:t.amount,from:t.time.from.toDate(),location:{connect:{id:e.id}},orderedAt:t.time.order.toDate(),orderId:t.orderId,price:t.price,to:t.time.to.toDate(),user:{connect:{id:r.id}}},update:{amount:t.amount,from:t.time.from.toDate(),location:{connect:{id:e.id}},price:t.price,to:t.time.to.toDate()},where:{orderId:t.orderId,userId:r.id}})}else if(t.type==="change")await i.event.update({data:{from:t.time.from.toDate(),to:t.time.to.toDate()},where:{orderId:t.orderId,userId:r.id}});else if(t.type==="cancel")await i.event.update({data:{canceledAt:t.cancelledAt.toDate()},where:{orderId:t.orderId,userId:r.id}});else if(t.type==="invoice")await i.event.update({data:{invoicedAt:t.invoicedAt.toDate()},where:{orderId:t.orderId,userId:r.id}});else throw new Error("Unknown email type!")}static async findUser(t){if(!t)throw new Error("Did not found a valid recipient!");let r=t.split("@")[0],e=await i.user.findUnique({where:{prefix:r}});if(!e)throw new Error(`User with email prefix ${r} not found!`);return e}static async getLocation(t){let r=await i.location.findFirst({where:{address:t.address,name:t.name}});if(!r){let e=w(t.name),{latitude:a,longitude:o}=await this.geocode(t.address);r=await i.location.create({data:{address:t.address,emoji:e,latitude:a,longitude:o,name:t.name}})}return r}static parseCancellationMail(t){let e=(t.subject||"").match(/\((\w+)\)/);if(e)return{cancelledAt:n(t.date),orderId:e[1],type:"cancel"}}static parseChangeMail(t){let r=[(t.html||"").match(/https:\/\/share.toogoodtogo.com\/receipts\/details\/(\w+)/),(t.html||"").match(/(\d{1,2}\.\d{2}\.\d{2}) zwischen (\d{1,2}:\d{2}) und (\d{1,2}:\d{2})(?: Uhr)? (\w+)+ \(/)];if(!r[0])throw new Error("Order ID not found!");if(!r[1])throw new Error("Date / Time not found!");let e=r[1][4];e==="MEZ"&&(e="MET");let a=n.tz(r[1][1]+" "+r[1][2],"DD.MM.YY HH:mm",e),o=n.tz(r[1][1]+" "+r[1][3],"DD.MM.YY HH:mm",e);return{orderId:r[0][1].trim(),time:{from:a,to:o},type:"change"}}static parseInvoiceMail(t){let e=(t.html||"").match(/Die Rechnung für deine Bestellung (\w+)/);if(e)return{invoicedAt:n(t.date),orderId:e[1],type:"invoice"};throw new Error("Order Id not found!")}static parseOrderMail(t){let r=t.html||"",e=[r.match(/\/order\/([^/]+)\//),r.match(/Wir bestätigen hiermit deine Bestellung bei ([^(.<]+)/),r.match(/<span>Du kannst deine Bestellung am (\d{1,2}\.\d{2}\.\d{2}) zwischen (\d{1,2}:\d{2}) und (\d{1,2}:\d{2}) Uhr (\w+)[^:]+: (.+).<\/span><\/div>/),r.match(/<span>Du kannst deine Bestellung zwischen (\d{1,2}\.\d{1,2}), (\d{1,2}:\d{2}) und (\d{1,2}:\d{2})[^:]+: (.+).<\/span><\/div>/),r.match(/<b>Datum:<\/b>\s+<span>(\d{1,2}\.\d{2}\.\d{2})<\/span>/),r.match(/Abholzeit:<\/b>\s+<span>(\d{1,2}:\d{2}) - (\d{1,2}:\d{2}) (\w+)/),r.match(/Anzahl: (\d+)/),r.match(/Anzahl:<\/b>\s+<span>(\d+)/),r.match(/Gesamtpreis: ([\d,.]+)[^\d,.]/),r.match(/Gesamtpreis:<\/b>\s+<span>([\d,.]+)[^\d,.]/),r.match(/Standort:<\/b>\s+<span>([^<]+)/)];if(!e[0])throw new Error("Order ID not found!");if(!e[1])throw new Error("Location name not found!");if(!e[2]&&!e[3]&&!(e[4]&&e[5]))throw new Error("Date, time and address not found (1)!");let a="MET";e[2]&&(a=e[2][4]),e[5]&&(a=e[5][3]),a==="MEZ"&&(a="MET");let o=n(t.date),d,s,p;if(e[2]&&(d=n.tz(e[2][1]+" "+e[2][2],"DD.MM.YY HH:mm",a),s=n.tz(e[2][1]+" "+e[2][3],"DD.MM.YY HH:mm",a),p=e[2][5].trim()),e[3]){let y=o.year();d=n.tz(e[3][1]+"."+y+" "+e[3][2],"DD.MM.YYYY HH:mm",a),s=n.tz(e[3][1]+"."+y+" "+e[3][3],"DD.MM.YYYY HH:mm",a),p=e[3][4].trim(),d.isBefore(o)&&d.add(1,"year"),s.isBefore(d)&&s.add(1,"year")}if(e[4]&&e[5]&&e[10]&&(d=n.tz(e[4][1]+" "+e[5][1],"DD.MM.YY HH:mm",a),s=n.tz(e[4][1]+" "+e[5][2],"DD.MM.YY HH:mm",a),p=e[10][1].trim()),!d||!s||!p)throw new Error("Date, time or address not found (2)!");let m=0;if(e[6])m=parseInt(e[6][1],10);else if(e[7])m=parseInt(e[7][1],10);else throw new Error("Amount not found!");if(isNaN(m))throw new Error("Amount (1) is not a number!");let f=0;if(e[8])f=parseInt(e[8][1].replace(/[.|,]/g,""));else if(e[9])f=parseInt(e[9][1].replace(/[.|,]/g,""));else throw new Error("Price not found!");if(isNaN(f))throw new Error("Price is not a number!");let h=E.decode(e[1][1].trim());return h.endsWith("!")&&(h=h.slice(0,-1)),{amount:m,location:{address:E.decode(p),name:h},orderId:e[0][1].trim(),price:f,time:{from:d,order:o,to:s},type:"order"}}};export{c as a,i as b,M as c};
|
|
2
|
-
//# sourceMappingURL=chunk-5TQHQ2B4.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/config.ts","../src/lib/db.ts","../src/lib/parser.ts","../src/lib/emoji.ts"],"sourcesContent":["import { init } from '@sentry/node';\nimport { readFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\ninit({\n dsn:\n process.env.SENTRY_DSN ||\n 'https://5e4630d58e5f4c778ce22140c53b3684@glitch.sebbo.net/9',\n});\n\nlet dir = dirname(fileURLToPath(import.meta.url));\nif (dir.endsWith('/dist')) {\n dir = resolve(dir, '..', 'src');\n} else {\n dir = resolve(dir, '..');\n}\n\nfunction src(path?: string) {\n return resolve(dir, path || '');\n}\n\nlet version: string | undefined;\ntry {\n const pkg = JSON.parse(readFileSync(src('../package.json'), 'utf8'));\n version = pkg.version;\n} catch (error) {\n console.log('Failed getting tgtg-ical version:');\n console.error(error);\n}\n\nexport default {\n baseMail: process.env.BASE_MAIL || '@tgtg-ical.sebbo.net',\n baseUrl: process.env.BASE_URL || 'https://tgtg-ical.sebbo.net',\n src,\n version,\n};\n","import { PrismaClient } from '@prisma/client';\n\nconst prisma = new PrismaClient();\nexport default prisma;\n","import type { Location, Mail, User } from '@prisma/client';\n\nimport { captureException } from '@sentry/node';\nimport he from 'he';\nimport { type ParsedMail, simpleParser } from 'mailparser';\nimport moment from 'moment-timezone';\n\nimport config from './config.js';\nimport Config from './config.js';\nimport prisma from './db.js';\nimport getEmoji from './emoji.js';\n\ntype AnyMail = (CancellationMail | ChangeMail | InvoiceMail | OrderMail) & {\n to: string;\n};\n\ninterface CancellationMail {\n cancelledAt: moment.Moment;\n orderId: string;\n type: 'cancel';\n}\n\ninterface ChangeMail {\n orderId: string;\n time: {\n from: moment.Moment;\n to: moment.Moment;\n };\n type: 'change';\n}\n\ninterface InvoiceMail {\n invoicedAt: moment.Moment;\n orderId: string;\n type: 'invoice';\n}\n\ninterface OrderMail {\n amount: number;\n location: {\n address: string;\n name: string;\n };\n orderId: string;\n price: number;\n time: {\n from: moment.Moment;\n order: moment.Moment;\n to: moment.Moment;\n };\n type: 'order';\n}\n\nexport default class Parser {\n public static async geocode(\n address: string,\n ): Promise<\n | { latitude: null; longitude: null }\n | { latitude: number; longitude: number }\n > {\n const response = await fetch(\n 'https://nominatim.openstreetmap.org/search?format=json&limit=1&q=' +\n encodeURIComponent(address),\n {\n headers: {\n Referer: config.baseUrl,\n 'User-Agent': `tgtg-ical/${config.version} (${config.baseUrl})`,\n },\n },\n );\n if (!response.ok) {\n throw new Error('Geocoding failed: ' + response.statusText);\n }\n\n // super simple way to ensure a maximum of 1 request per second in cronjobs\n await new Promise((resolve) => setTimeout(resolve, 1000));\n\n const data = await response.json();\n if (!Array.isArray(data) || data.length === 0) {\n return {\n latitude: null,\n longitude: null,\n };\n }\n\n return {\n latitude: parseFloat(data[0].lat),\n longitude: parseFloat(data[0].lon),\n };\n }\n\n public static async handleMail(mail: Mail) {\n try {\n const parsed = await this.parseMail(mail.raw);\n if (parsed) {\n await this.applyParsedMail(parsed);\n }\n\n await prisma.mail.delete({\n where: {\n id: mail.id,\n },\n });\n } catch (error) {\n const errorId = captureException(error);\n await prisma.mail.update({\n data: {\n error: error instanceof Error ? error.stack : String(error),\n erroredAt: new Date(),\n errorId,\n version: config.version,\n },\n where: {\n id: mail.id,\n },\n });\n }\n }\n\n public static async inhaleMail(email: string): Promise<void> {\n const mail = await prisma.mail.create({\n data: {\n raw: email,\n },\n });\n\n await this.handleMail(mail);\n }\n\n public static async parseMail(\n mail: string,\n baseMailPostfix = config.baseMail,\n ): Promise<AnyMail | undefined> {\n // parse email\n const email = await simpleParser(mail, {\n skipHtmlToText: true,\n skipImageLinks: true,\n skipTextLinks: true,\n skipTextToHtml: true,\n });\n\n if (!email.from?.value[0].address?.endsWith('toogoodtogo.com')) {\n throw new Error('Not a TGTG email!');\n }\n\n let to: string | undefined = (\n Array.isArray(email.to) ? email.to : [email.to]\n )\n .map((to) => to?.value)\n .flat()\n .filter((address) => !!address)\n .map((address) => address.address)\n .find((address) => address?.endsWith(baseMailPostfix));\n\n if (!to) {\n const received = email.headers.get('received');\n const regexp = new RegExp(`([\\\\w-]+${Config.baseMail})`, 'i');\n if (Array.isArray(received)) {\n received.forEach((r) => {\n const s = typeof r === 'string' ? r : r.value;\n const match = s.match(regexp);\n if (match) {\n to = match[1];\n }\n });\n }\n }\n if (!to) {\n throw new Error('No recipient found!');\n }\n\n // Order confirmation\n if (email.headers.get('x-pm-tag') === 'consumer_order_confirm') {\n const order = this.parseOrderMail(email);\n return {\n to,\n ...order,\n };\n }\n\n // Time Changed\n if (email.headers.get('x-pm-tag') === 'collection_time_changed') {\n const change = this.parseChangeMail(email);\n return {\n to,\n ...change,\n };\n }\n\n // Cancellation\n if (email.headers.get('x-pm-tag') === 'consumer_order_reverted') {\n const cancellation = this.parseCancellationMail(email);\n if (cancellation) {\n return {\n to,\n ...cancellation,\n };\n }\n }\n\n // is invoice?\n if (email.headers.get('x-pm-tag') === 'invoice') {\n const invoice = this.parseInvoiceMail(email);\n if (invoice) {\n return {\n to,\n ...invoice,\n };\n }\n }\n\n // Non-transactional email\n if (\n !email.headers.get('x-pm-tag') &&\n !email.headers.get('x-pm-message-id')\n ) {\n return undefined;\n }\n\n // Unsupported email\n if (email.headers.get('x-pm-tag')) {\n throw new Error(\n `Unsupported email type: ${email.headers.get('x-pm-tag')}`,\n );\n }\n\n throw new Error('Not implemented!');\n }\n\n public static async runCleanup(): Promise<void> {\n const mails = await prisma.mail.findMany({\n orderBy: {\n erroredAt: 'asc',\n },\n take: 10,\n where: {\n OR: [\n { error: null },\n { version: null },\n { version: { not: config.version } },\n ],\n },\n });\n\n for (const mail of mails) {\n await this.handleMail(mail);\n }\n\n // Cleanup Users\n await prisma.user.deleteMany({\n where: {\n OR: [\n {\n lastSeenAt: {\n lt: moment().subtract(8, 'weeks').toDate(),\n },\n },\n {\n createdAt: {\n lt: moment().subtract(3, 'hours').toDate(),\n },\n lastSeenAt: {\n equals: prisma.user.fields.createdAt,\n },\n },\n ],\n },\n });\n\n // Cleanup Events\n await prisma.event.deleteMany({\n where: {\n to: {\n lt: moment().subtract(4, 'weeks').toDate(),\n },\n },\n });\n\n // Cleanup Mails\n await prisma.mail.deleteMany({\n where: {\n createdAt: {\n lt: moment().subtract(2, 'weeks').toDate(),\n },\n },\n });\n }\n\n private static async applyParsedMail(email: AnyMail): Promise<void> {\n const user = await this.findUser(email.to);\n\n if (email.type === 'order') {\n const location = await this.getLocation(email.location);\n\n await prisma.event.upsert({\n create: {\n amount: email.amount,\n from: email.time.from.toDate(),\n location: {\n connect: {\n id: location.id,\n },\n },\n orderedAt: email.time.order.toDate(),\n orderId: email.orderId,\n price: email.price,\n to: email.time.to.toDate(),\n user: {\n connect: {\n id: user.id,\n },\n },\n },\n update: {\n amount: email.amount,\n from: email.time.from.toDate(),\n location: {\n connect: {\n id: location.id,\n },\n },\n price: email.price,\n to: email.time.to.toDate(),\n },\n where: {\n orderId: email.orderId,\n userId: user.id,\n },\n });\n } else if (email.type === 'change') {\n await prisma.event.update({\n data: {\n from: email.time.from.toDate(),\n to: email.time.to.toDate(),\n },\n where: {\n orderId: email.orderId,\n userId: user.id,\n },\n });\n } else if (email.type === 'cancel') {\n await prisma.event.update({\n data: {\n canceledAt: email.cancelledAt.toDate(),\n },\n where: {\n orderId: email.orderId,\n userId: user.id,\n },\n });\n } else if (email.type === 'invoice') {\n await prisma.event.update({\n data: {\n invoicedAt: email.invoicedAt.toDate(),\n },\n where: {\n orderId: email.orderId,\n userId: user.id,\n },\n });\n } else {\n throw new Error('Unknown email type!');\n }\n }\n\n private static async findUser(to: string): Promise<User> {\n if (!to) {\n throw new Error('Did not found a valid recipient!');\n }\n\n const prefix = to.split('@')[0];\n const user = await prisma.user.findUnique({\n where: { prefix },\n });\n if (!user) {\n throw new Error(`User with email prefix ${prefix} not found!`);\n }\n\n return user;\n }\n\n private static async getLocation(\n input: OrderMail['location'],\n ): Promise<Location> {\n let location = await prisma.location.findFirst({\n where: {\n address: input.address,\n name: input.name,\n },\n });\n if (!location) {\n const emoji = getEmoji(input.name);\n const { latitude, longitude } = await this.geocode(input.address);\n location = await prisma.location.create({\n data: {\n address: input.address,\n emoji,\n latitude,\n longitude,\n name: input.name,\n },\n });\n }\n\n return location;\n }\n\n private static parseCancellationMail(\n email: ParsedMail,\n ): CancellationMail | undefined {\n const subject = email.subject || '';\n const match = subject.match(/\\((\\w+)\\)/);\n if (match) {\n return {\n cancelledAt: moment(email.date),\n orderId: match[1],\n type: 'cancel',\n };\n }\n }\n\n private static parseChangeMail(email: ParsedMail): ChangeMail {\n const matches = [\n (email.html || '').match(\n /https:\\/\\/share.toogoodtogo.com\\/receipts\\/details\\/(\\w+)/,\n ),\n (email.html || '').match(\n /(\\d{1,2}\\.\\d{2}\\.\\d{2}) zwischen (\\d{1,2}:\\d{2}) und (\\d{1,2}:\\d{2})(?: Uhr)? (\\w+)+ \\(/,\n ),\n ];\n if (!matches[0]) {\n throw new Error('Order ID not found!');\n }\n if (!matches[1]) {\n throw new Error('Date / Time not found!');\n }\n\n let timezone = matches[1][4];\n if (timezone === 'MEZ') {\n timezone = 'MET';\n }\n\n const from = moment.tz(\n matches[1][1] + ' ' + matches[1][2],\n 'DD.MM.YY HH:mm',\n timezone,\n );\n const to = moment.tz(\n matches[1][1] + ' ' + matches[1][3],\n 'DD.MM.YY HH:mm',\n timezone,\n );\n\n return {\n orderId: matches[0][1].trim(),\n time: {\n from,\n to,\n },\n type: 'change',\n };\n }\n\n private static parseInvoiceMail(email: ParsedMail): InvoiceMail {\n const html = email.html || '';\n const match = html.match(/Die Rechnung für deine Bestellung (\\w+)/);\n if (match) {\n return {\n invoicedAt: moment(email.date),\n orderId: match[1],\n type: 'invoice',\n };\n }\n\n throw new Error('Order Id not found!');\n }\n\n private static parseOrderMail(email: ParsedMail): OrderMail {\n const html = email.html || '';\n const matches = [\n html.match(/\\/order\\/([^/]+)\\//),\n html.match(/Wir bestätigen hiermit deine Bestellung bei ([^(.<]+)/),\n html.match(\n /<span>Du kannst deine Bestellung am (\\d{1,2}\\.\\d{2}\\.\\d{2}) zwischen (\\d{1,2}:\\d{2}) und (\\d{1,2}:\\d{2}) Uhr (\\w+)[^:]+: (.+).<\\/span><\\/div>/,\n ),\n html.match(\n /<span>Du kannst deine Bestellung zwischen (\\d{1,2}\\.\\d{1,2}), (\\d{1,2}:\\d{2}) und (\\d{1,2}:\\d{2})[^:]+: (.+).<\\/span><\\/div>/,\n ),\n html.match(\n /<b>Datum:<\\/b>\\s+<span>(\\d{1,2}\\.\\d{2}\\.\\d{2})<\\/span>/,\n ),\n html.match(\n /Abholzeit:<\\/b>\\s+<span>(\\d{1,2}:\\d{2}) - (\\d{1,2}:\\d{2}) (\\w+)/,\n ),\n html.match(/Anzahl: (\\d+)/),\n html.match(/Anzahl:<\\/b>\\s+<span>(\\d+)/),\n html.match(/Gesamtpreis: ([\\d,.]+)[^\\d,.]/),\n html.match(/Gesamtpreis:<\\/b>\\s+<span>([\\d,.]+)[^\\d,.]/),\n html.match(/Standort:<\\/b>\\s+<span>([^<]+)/),\n ];\n if (!matches[0]) {\n throw new Error('Order ID not found!');\n }\n if (!matches[1]) {\n throw new Error('Location name not found!');\n }\n if (!matches[2] && !matches[3] && !(matches[4] && matches[5])) {\n throw new Error('Date, time and address not found (1)!');\n }\n\n let timezone = 'MET';\n if (matches[2]) {\n timezone = matches[2][4];\n }\n if (matches[5]) {\n timezone = matches[5][3];\n }\n if (timezone === 'MEZ') {\n timezone = 'MET';\n }\n\n const now = moment(email.date);\n let from: moment.Moment | undefined;\n let to: moment.Moment | undefined;\n let address: string | undefined;\n\n if (matches[2]) {\n from = moment.tz(\n matches[2][1] + ' ' + matches[2][2],\n 'DD.MM.YY HH:mm',\n timezone,\n );\n to = moment.tz(\n matches[2][1] + ' ' + matches[2][3],\n 'DD.MM.YY HH:mm',\n timezone,\n );\n address = matches[2][5].trim();\n }\n if (matches[3]) {\n const year = now.year();\n from = moment.tz(\n matches[3][1] + '.' + year + ' ' + matches[3][2],\n 'DD.MM.YYYY HH:mm',\n timezone,\n );\n to = moment.tz(\n matches[3][1] + '.' + year + ' ' + matches[3][3],\n 'DD.MM.YYYY HH:mm',\n timezone,\n );\n address = matches[3][4].trim();\n\n if (from.isBefore(now)) {\n from.add(1, 'year');\n }\n if (to.isBefore(from)) {\n to.add(1, 'year');\n }\n }\n if (matches[4] && matches[5] && matches[10]) {\n from = moment.tz(\n matches[4][1] + ' ' + matches[5][1],\n 'DD.MM.YY HH:mm',\n timezone,\n );\n to = moment.tz(\n matches[4][1] + ' ' + matches[5][2],\n 'DD.MM.YY HH:mm',\n timezone,\n );\n address = matches[10][1].trim();\n }\n\n if (!from || !to || !address) {\n throw new Error('Date, time or address not found (2)!');\n }\n\n let amount = 0;\n if (matches[6]) {\n amount = parseInt(matches[6][1], 10);\n } else if (matches[7]) {\n amount = parseInt(matches[7][1], 10);\n } else {\n throw new Error('Amount not found!');\n }\n if (isNaN(amount)) {\n throw new Error('Amount (1) is not a number!');\n }\n\n let price = 0;\n if (matches[8]) {\n price = parseInt(matches[8][1].replace(/[.|,]/g, ''));\n } else if (matches[9]) {\n price = parseInt(matches[9][1].replace(/[.|,]/g, ''));\n } else {\n throw new Error('Price not found!');\n }\n if (isNaN(price)) {\n throw new Error('Price is not a number!');\n }\n\n let name = he.decode(matches[1][1].trim());\n if (name.endsWith('!')) {\n name = name.slice(0, -1);\n }\n\n return {\n amount,\n location: {\n address: he.decode(address),\n name,\n },\n orderId: matches[0][1].trim(),\n price,\n time: {\n from,\n order: now,\n to,\n },\n type: 'order',\n };\n }\n}\n","export const DEFAULT_EMOJI = '🍴';\nexport const EMOJIS: Record<string, RegExp[]> = {\n '🌭': [/Ikea/],\n '🌮': [/Enchilada/, /Besitos/],\n '🍔': [\n /Burger/,\n /McDonald[‘|']?s/,\n /Burger King/,\n /Hans im Glück/,\n /Peter Pane/,\n ],\n '🍕': [\n /Domino‘s/,\n /Pizza Hut/,\n /L[‘|']Osteria/,\n /Call a Pizza/,\n /Smiley[‘|']s Pizza/,\n ],\n '🍗': [/KFC/],\n '🍝': [/LaTagliatella/, /Vapiano/],\n '🍤': [/Nordsee/],\n '🍩': [/Donut/, /Dunkin/],\n '🍪': [/Starbucks/],\n '🥐': [/LeCroBag/],\n '🥖': [\n /Bäckerei/,\n /Back/,\n /BackWerk/,\n /Kamps/,\n /Kamps Backstuben/,\n /Junge Die Bäckerei/,\n /Back-Factory/,\n ],\n '🥗': [/dean ?& ?david/],\n '🥨': [/Brezel/, /Ditsch/],\n '🥩': [/Steakhouse/, /Block House/, /Jim Block/],\n '🥪': [\n /Sandwich/,\n /Tank ?& ?Rast/,\n /T&R Raststätten/,\n /Autohöfe/,\n /Aral/,\n /Shell/,\n /Jet Tank/,\n /Subway/,\n /Caf[é|e] bonjour/,\n /Total Deutschland/,\n /Esso:? Snack ?& ?Shop/,\n ],\n '🛒': [\n /Edeka/,\n /Netto/,\n /Rewe/,\n /Penny/,\n /Lidl/,\n /Kaufland/,\n /Aldi/,\n /dm/,\n /Rossmann/,\n /Globus/,\n /Metro/,\n /Norma/,\n /Tegut/,\n ],\n};\n\nexport default function getEmoji(location: string): null | string {\n for (const emoji in EMOJIS) {\n const regExps = EMOJIS[emoji].map((name) => new RegExp(name, 'i'));\n const match = !!regExps.find((regExp) => regExp.test(location));\n if (match) {\n return emoji;\n }\n }\n\n return null;\n}\n"],"mappings":"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","names":["init","readFileSync","dirname","resolve","fileURLToPath","dir","src","path","version","error","config_default","PrismaClient","prisma","db_default","captureException","he","simpleParser","moment","EMOJIS","getEmoji","location","emoji","name","regExp","Parser","address","response","config_default","resolve","data","mail","parsed","db_default","error","errorId","captureException","email","baseMailPostfix","simpleParser","to","received","regexp","r","match","order","change","cancellation","invoice","mails","moment","user","location","prefix","input","emoji","getEmoji","latitude","longitude","matches","timezone","from","html","now","year","amount","price","name","he"]}
|