Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88ad16c86f | ||
|
|
45ce268db6 | ||
|
|
c1ab18fd9f | ||
|
|
52d6457797 | ||
|
|
4c9be79282 | ||
|
|
324f0f706f | ||
|
|
f7a8c1816f | ||
|
|
d14914a453 | ||
|
|
2a1d56d2fc | ||
|
|
c8ed065486 | ||
|
|
8e6c1924b8 | ||
|
|
04dbd0bb0c | ||
|
|
9b697fbb05 | ||
|
|
48ae3d8166 | ||
|
|
4643ab9b59 |
@@ -39,8 +39,9 @@ RUN npm ci --omit=dev || npm install --production && \
|
|||||||
RUN apk del python3 make g++ vips-dev
|
RUN apk del python3 make g++ vips-dev
|
||||||
|
|
||||||
# Copy built files from builder
|
# Copy built files from builder
|
||||||
|
# Hinweis: Drizzle-Migrationen werden nicht kopiert - das Schema wird zur
|
||||||
|
# Laufzeit von initDatabase() angelegt, src/db/migrations existiert nicht.
|
||||||
COPY --from=builder /app/dist ./dist
|
COPY --from=builder /app/dist ./dist
|
||||||
COPY --from=builder /app/src/db/migrations ./dist/db/migrations
|
|
||||||
|
|
||||||
# Copy migration script and migrated images
|
# Copy migration script and migrated images
|
||||||
COPY --from=builder /app/migrate-production.js ./migrate-production.js
|
COPY --from=builder /app/migrate-production.js ./migrate-production.js
|
||||||
|
|||||||
@@ -1,43 +1,84 @@
|
|||||||
import simpleGit, { SimpleGit } from 'simple-git';
|
import simpleGit, { SimpleGit } from 'simple-git';
|
||||||
import { mkdir, rm } from 'fs/promises';
|
import { mkdir, rm, cp } from 'fs/promises';
|
||||||
|
import { existsSync } from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { env } from '../config/env.js';
|
import { env } from '../config/env.js';
|
||||||
|
|
||||||
export class GitService {
|
export class GitService {
|
||||||
private git: SimpleGit;
|
private git: SimpleGit;
|
||||||
private workspaceDir: string;
|
private workspaceDir: string;
|
||||||
|
private parentDir: string;
|
||||||
private repoUrl: string;
|
private repoUrl: string;
|
||||||
private token: string;
|
private token: string;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.workspaceDir = env.GIT_WORKSPACE_DIR;
|
this.workspaceDir = env.GIT_WORKSPACE_DIR;
|
||||||
|
this.parentDir = path.dirname(this.workspaceDir);
|
||||||
this.repoUrl = env.GIT_REPO_URL;
|
this.repoUrl = env.GIT_REPO_URL;
|
||||||
this.token = env.GIT_TOKEN;
|
this.token = env.GIT_TOKEN;
|
||||||
this.git = simpleGit();
|
this.git = simpleGit();
|
||||||
}
|
}
|
||||||
|
|
||||||
async initialize() {
|
async initialize() {
|
||||||
// Ensure workspace directory exists
|
// Elternverzeichnis muss existieren - simple-git startet git von dort aus
|
||||||
await mkdir(this.workspaceDir, { recursive: true });
|
await mkdir(this.parentDir, { recursive: true });
|
||||||
|
|
||||||
// Add token to repo URL for authentication
|
// Add token to repo URL for authentication
|
||||||
const authenticatedUrl = this.repoUrl.replace(
|
const authenticatedUrl = this.repoUrl.replace(
|
||||||
'https://',
|
'https://',
|
||||||
`https://oauth2:${this.token}@`
|
`https://oauth2:${encodeURIComponent(this.token)}@`
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
let usable = false;
|
||||||
// Check if repo already exists
|
|
||||||
await this.git.cwd(this.workspaceDir);
|
if (existsSync(path.join(this.workspaceDir, '.git'))) {
|
||||||
await this.git.status();
|
try {
|
||||||
console.log('Repository already exists, pulling latest...');
|
this.git = simpleGit(this.workspaceDir);
|
||||||
await this.git.pull();
|
await this.git.status();
|
||||||
} catch {
|
console.log('Repository already exists, pulling latest...');
|
||||||
// Clone if doesn't exist
|
await this.git.pull();
|
||||||
|
usable = true;
|
||||||
|
} catch (error) {
|
||||||
|
// Token aus der Meldung entfernen - git gibt die Remote-URL mit aus
|
||||||
|
const msg = error instanceof Error ? error.message : String(error);
|
||||||
|
console.warn(
|
||||||
|
'Existing workspace unusable, re-cloning:',
|
||||||
|
msg.replace(/\/\/[^@\s/]*@/g, '//***@')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!usable) {
|
||||||
console.log('Cloning repository...');
|
console.log('Cloning repository...');
|
||||||
|
|
||||||
|
// Hochgeladene Bilder liegen im Workspace und wuerden beim Loeschen
|
||||||
|
// verschwinden - vorher wegsichern, nach dem Clone zurueckspielen
|
||||||
|
const imagesDir = path.join(this.workspaceDir, 'public', 'images');
|
||||||
|
const backupDir = path.join(this.parentDir, '.workspace-images-backup');
|
||||||
|
const hasImages = existsSync(imagesDir);
|
||||||
|
|
||||||
|
await rm(backupDir, { recursive: true, force: true });
|
||||||
|
if (hasImages) {
|
||||||
|
await cp(imagesDir, backupDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
await rm(this.workspaceDir, { recursive: true, force: true });
|
await rm(this.workspaceDir, { recursive: true, force: true });
|
||||||
|
|
||||||
|
// Aus dem existierenden Elternverzeichnis klonen, nicht aus dem
|
||||||
|
// soeben geloeschten Zielverzeichnis (sonst: spawn git ENOENT)
|
||||||
|
this.git = simpleGit(this.parentDir);
|
||||||
await this.git.clone(authenticatedUrl, this.workspaceDir);
|
await this.git.clone(authenticatedUrl, this.workspaceDir);
|
||||||
await this.git.cwd(this.workspaceDir);
|
this.git = simpleGit(this.workspaceDir);
|
||||||
|
|
||||||
|
if (hasImages) {
|
||||||
|
// force: false -> was schon im Repo liegt, bleibt unangetastet
|
||||||
|
await cp(backupDir, imagesDir, {
|
||||||
|
recursive: true,
|
||||||
|
force: false,
|
||||||
|
errorOnExist: false,
|
||||||
|
});
|
||||||
|
await rm(backupDir, { recursive: true, force: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure git user
|
// Configure git user
|
||||||
@@ -47,6 +88,14 @@ export class GitService {
|
|||||||
|
|
||||||
async commitAndPush(message: string): Promise<string> {
|
async commitAndPush(message: string): Promise<string> {
|
||||||
await this.git.add('.');
|
await this.git.add('.');
|
||||||
|
|
||||||
|
const status = await this.git.status();
|
||||||
|
if (status.isClean()) {
|
||||||
|
// Nichts zu committen - aktuellen Stand zurueckgeben statt zu scheitern
|
||||||
|
const current = await this.git.log({ maxCount: 1 });
|
||||||
|
return current.latest?.hash || '';
|
||||||
|
}
|
||||||
|
|
||||||
await this.git.commit(message);
|
await this.git.commit(message);
|
||||||
await this.git.push('origin', 'main');
|
await this.git.push('origin', 'main');
|
||||||
|
|
||||||
@@ -59,7 +108,15 @@ export class GitService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async reset() {
|
async reset() {
|
||||||
await this.git.reset(['--hard', 'HEAD']);
|
// Nur zuruecksetzen wenn wirklich ein Repo da ist - sonst laeuft git
|
||||||
await this.git.clean('f', ['-d']);
|
// im Prozess-Arbeitsverzeichnis und raeumt dort auf
|
||||||
|
if (!existsSync(path.join(this.workspaceDir, '.git'))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const git = simpleGit(this.workspaceDir);
|
||||||
|
await git.reset(['--hard', 'HEAD']);
|
||||||
|
// Uploads ausnehmen - die sind noch nicht committed und waeren sonst weg
|
||||||
|
await git.clean('f', ['-d', '-e', 'public/images']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 138 KiB |
|
After Width: | Height: | Size: 170 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 153 KiB |
|
After Width: | Height: | Size: 162 KiB |
|
After Width: | Height: | Size: 168 KiB |
|
After Width: | Height: | Size: 168 KiB |
|
After Width: | Height: | Size: 129 KiB |
|
After Width: | Height: | Size: 1021 KiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 488 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="500" zoomAndPan="magnify" viewBox="0 0 375 374.999991" height="500" preserveAspectRatio="xMidYMid meet" version="1.0"><defs><clipPath id="f68ef4028f"><path d="M 47.203125 40 L 322 40 L 322 335 L 47.203125 335 Z M 47.203125 40 " clip-rule="nonzero"/></clipPath></defs><g clip-path="url(#f68ef4028f)"><path fill="#1d6b32" d="M 48.097656 139.574219 C 48.097656 128.285156 48.660156 119.429688 55.417969 109.972656 C 60.960938 102.21875 68.625 96.976562 75.371094 90.4375 C 90.03125 76.242188 102.058594 52.597656 122.386719 45.964844 C 140.441406 40.078125 161.71875 50.683594 170.175781 67.148438 C 174.488281 75.5625 175.570312 84.835938 176.609375 94.097656 C 178.023438 106.769531 179.671875 119.417969 181.199219 132.078125 C 186.097656 127.304688 184.324219 113.089844 184.800781 106.679688 C 185.414062 98.355469 185.589844 89.773438 187.167969 81.554688 C 190.136719 66.023438 202.230469 53.867188 215.535156 46.148438 C 230.378906 37.53125 245.867188 37.894531 259.476562 48.902344 C 265.457031 53.734375 269.027344 59.921875 273.558594 65.980469 C 278.105469 72.058594 283.742188 77.164062 289.878906 81.59375 C 301.03125 89.632812 313.222656 97.105469 314.707031 111.992188 C 315.859375 123.574219 312.664062 136.851562 306.261719 146.585938 C 298.824219 157.886719 283.566406 165.484375 271.140625 169.84375 C 263.703125 172.453125 256.171875 173.589844 248.375 174.402344 C 243.988281 174.855469 239.605469 175.347656 235.230469 175.863281 C 233.320312 176.085938 220.464844 177.1875 222.21875 178.914062 C 223.414062 180.097656 232.449219 178.90625 234.25 178.929688 C 238.816406 178.984375 243.378906 179.058594 247.9375 179.101562 C 258.195312 179.199219 268.472656 179.238281 278.703125 179.984375 C 294.078125 181.101562 308.125 186.960938 316.167969 200.828125 C 324.128906 214.566406 322.324219 235.332031 313.648438 248.554688 C 309.550781 254.800781 302.960938 258.933594 298.382812 264.773438 C 292.863281 271.808594 289.753906 280.417969 284.703125 287.777344 C 277.070312 298.902344 265.578125 308.597656 251.328125 307.664062 C 237.253906 306.738281 223.84375 295.984375 214.992188 285.644531 C 204.679688 273.609375 202.425781 260.40625 198.433594 245.617188 C 197.992188 243.980469 196.5 234.824219 195.105469 234.082031 C 192.15625 232.503906 193.15625 242.25 193.140625 243.652344 C 193.039062 252.289062 193.183594 260.898438 194.160156 269.492188 C 195.984375 285.542969 200.703125 301.367188 211.675781 313.625 C 215.640625 318.050781 226.738281 326.539062 219.757812 333.71875 C 216.042969 337.535156 203.546875 329.980469 199.726562 326.988281 C 169.355469 303.21875 175.738281 257.648438 175.738281 223.953125 C 158.667969 247.144531 172.769531 289.511719 141.984375 304.472656 C 130.417969 310.089844 113.792969 310.679688 102.148438 305.070312 C 88.4375 298.476562 81.277344 282.652344 73.429688 270.453125 C 69.234375 263.933594 63.84375 258.296875 58.707031 252.453125 C 55.953125 249.324219 52.542969 246.261719 50.21875 242.816406 C 47.457031 238.734375 47.503906 233.292969 48.097656 228.109375 C 49.5 215.78125 54.359375 203.136719 63.367188 194.40625 C 72.792969 185.277344 84.792969 181.804688 97.621094 181.160156 C 106.09375 180.734375 114.582031 180.5625 123.0625 180.191406 C 127.40625 180.003906 131.675781 179.730469 135.988281 179.113281 C 141.285156 178.359375 145.921875 177.105469 138.335938 175.230469 C 109.652344 168.167969 59.332031 176.03125 48.097656 139.574219 C 48.097656 135.066406 52.933594 155.265625 48.097656 139.574219 " fill-opacity="1" fill-rule="nonzero"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 3.5 KiB |
@@ -15,6 +15,7 @@ import "../styles/index.css"
|
|||||||
|
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
||||||
<title>Gallus Pub</title>
|
<title>Gallus Pub</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|||||||
@@ -28,52 +28,44 @@ Plätze sind begrenzt! Jetzt reservieren unter 🍀WA 077 232 27 70
|
|||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
image: "/images/events/ml0s9u8a-d8eqee.jpeg",
|
image: "/images/events/mr82c7eh-yp87hy.jpeg",
|
||||||
title: "St.Patricks Day",
|
title: "Richie Live",
|
||||||
date: "2026-03-17",
|
date: "2026-08-27",
|
||||||
description: `
|
description: `
|
||||||
🍀 It’s Paddy’s Time! Freu dich auf echtes St.-Patrick’s-Day-Feeling mit Live‑Dudelsackmusik, Guinness vom Fass und natürlich grünem Bier. Zieh etwas Grünes an, bring deine Freunde mit und stoß mit uns an – Sláinte! 🍻
|
SOLD OUT! - Richie hat das Image eines Weltenbummlers und Musikkünstlers. In der Ostschweiz ist er bereits bestens bekannt.🍀Warteliste: WA 077 232 27 70
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
image: "/images/events/mk6wdnz2-rpxzvl.jpeg",
|
image: "/images/events/mrnpux59-b3075p.jpeg",
|
||||||
title: "Pg Petricca - LIVE",
|
title: "Hannes LIVE",
|
||||||
date: "2026-03-20",
|
date: "2026-09-10",
|
||||||
description: `
|
description: `
|
||||||
LIVE Musik mit Pg Petricca! - Folk & Blues.
|
Er ist zurück!🥰🍀Johannes ist wieder bei uns! Eine weitere unvergessliche Irish-Night!!🍀Sei dabei! Reservationen🍀via WA 077 232 27 70
|
||||||
Eintritt ist Frei / Hutkollekte
|
|
||||||
Reservation unter 🍀WA 077 232 27 70
|
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
image: "/images/events/mmnlxydh-924q8d.jpeg",
|
image: "/images/events/mrngoyyy-49rz7u.jpeg",
|
||||||
title: "Chris Live",
|
title: "Danielle&Nina",
|
||||||
date: "2026-04-16",
|
date: "2026-09-24",
|
||||||
description: `
|
description: `
|
||||||
Guitar & Songwriter. Geboren in den USA und geprägt von einem Leben voller Bewegung und Musik.
|
SOLD OUT! - First time on stage – und das direkt im Gallus Pub!🎤✨
|
||||||
🍀WA 077 232 27 70
|
Danielle & Nina bringen Irish Folk & liebevolle Cover Songs.🍀Warteliste: WA 077 232 27 70
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
image: "/images/events/mmnlz7pc-wwdvwe.jpeg",
|
|
||||||
title: "Aushilfe gesucht",
|
|
||||||
date: "2026-03-12",
|
|
||||||
description: `
|
|
||||||
🍀4 Abende im Monat oder nach Absprache🍀Die besten Stammgäste 🍀Gute Entlöhnung 🍀Familiäre Atmosphäre und mehr! WA 077 232 27 70
|
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const images = [
|
const images = [
|
||||||
{ src: "/images/gallery/miywxkwh-m4xaww.webp", alt: "miywxkwh-m4xaww.webp" },
|
{ src: "/images/gallery/mndhrrtl-s4o8dn.png", alt: "mndhrrtl-s4o8dn.png" },
|
||||||
{ src: "/images/gallery/miyxgbqr-n3zzrg.png", alt: "miyxgbqr-n3zzrg.png" },
|
{ src: "/images/gallery/mndhtjvz-965yra.jpeg", alt: "mndhtjvz-965yra.jpeg" },
|
||||||
{ src: "/images/gallery/miyxgfh1-c7zawh.png", alt: "miyxgfh1-c7zawh.png" },
|
{ src: "/images/gallery/mndi3625-lnnggc.jpeg", alt: "mndi3625-lnnggc.jpeg" },
|
||||||
{ src: "/images/gallery/miyxgjff-wjtyim.png", alt: "miyxgjff-wjtyim.png" },
|
{ src: "/images/gallery/mndi7upa-qxukqg.jpeg", alt: "mndi7upa-qxukqg.jpeg" },
|
||||||
{ src: "/images/gallery/miyxgn6h-jsaltu.png", alt: "miyxgn6h-jsaltu.png" },
|
{ src: "/images/gallery/mndi8kzg-oazjp8.jpeg", alt: "mndi8kzg-oazjp8.jpeg" },
|
||||||
{ src: "/images/gallery/mj67l5x3-pdasw8.jpeg", alt: "mj67l5x3-pdasw8.jpeg" },
|
{ src: "/images/gallery/mndiabuo-m29xj0.jpeg", alt: "mndiabuo-m29xj0.jpeg" },
|
||||||
{ src: "/images/gallery/mj67mw2z-3pd81q.jpeg", alt: "mj67mw2z-3pd81q.jpeg" },
|
{ src: "/images/gallery/mndicr59-n8suoy.jpeg", alt: "mndicr59-n8suoy.jpeg" },
|
||||||
{ src: "/images/gallery/mj67nwjs-6oaijj.jpeg", alt: "mj67nwjs-6oaijj.jpeg" },
|
{ src: "/images/gallery/mndieqns-mjs7xe.jpeg", alt: "mndieqns-mjs7xe.jpeg" },
|
||||||
{ src: "/images/gallery/mj67ove6-el3pf7.png", alt: "mj67ove6-el3pf7.png" }
|
{ src: "/images/gallery/mndif8nv-aptjf6.jpeg", alt: "mndif8nv-aptjf6.jpeg" },
|
||||||
|
{ src: "/images/gallery/mndiggta-hnldkv.jpeg", alt: "mndiggta-hnldkv.jpeg" },
|
||||||
|
{ src: "/images/gallery/mndih8lp-woprt4.webp", alt: "mndih8lp-woprt4.webp" }
|
||||||
];
|
];
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||