diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml index 8edaae1..2a29c40 100644 --- a/.forgejo/workflows/test.yml +++ b/.forgejo/workflows/test.yml @@ -21,16 +21,16 @@ jobs: playwright: runs-on: ubuntu-latest needs: vitest - services: - mongo: - image: mongo:7 - ports: - - 27017:27017 env: - MONGODB_URI: mongodb://localhost:27017/ghostguild-test + MONGODB_URI: mongodb://mongo-ci:27017/ghostguild-test JWT_SECRET: ci-test-jwt-secret + RESEND_API_KEY: re_ci_dummy_not_used + HELCIM_API_TOKEN: helcim_ci_dummy_not_used + OIDC_COOKIE_SECRET: ci-oidc-cookie-secret-not-secret NUXT_PUBLIC_COMING_SOON: 'false' NODE_ENV: development + ALLOW_DEV_TEST_ENDPOINTS: 'true' + BASE_URL: http://localhost:3000 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -39,15 +39,35 @@ jobs: cache: npm - run: npm ci - run: npx playwright install --with-deps chromium + - name: Start MongoDB + run: | + docker rm -f mongo-ci 2>/dev/null || true + docker run -d --name mongo-ci mongo:7 + # Forgejo runs each job inside its own container; attach Mongo to + # that container's network so MONGODB_URI=mongodb://mongo-ci:27017 + # resolves from inside the runner. + RUNNER_NET=$(docker inspect "$HOSTNAME" --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{end}}' | awk '{print $1}') + docker network connect "$RUNNER_NET" mongo-ci + docker ps + - name: Wait for MongoDB + run: timeout 30 sh -c 'until docker exec mongo-ci mongosh --quiet --eval "1" >/dev/null 2>&1; do sleep 1; done' + - name: MongoDB log on failure + if: failure() + run: docker logs mongo-ci || true + - name: Seed test data + run: node scripts/seed-all.js && node scripts/seed-tags.js - run: npm run build - name: Start server - run: node .output/server/index.mjs & + run: node .output/server/index.mjs > /tmp/server.log 2>&1 & env: PORT: 3000 - name: Wait for server run: timeout 30 sh -c 'until curl -sf http://localhost:3000; do sleep 1; done' - - run: npx playwright test --ignore-snapshots - - uses: actions/upload-artifact@v4 + - name: Server log on failure + if: failure() + run: cat /tmp/server.log || true + - run: npx playwright test + - uses: actions/upload-artifact@v3 if: failure() with: name: playwright-report @@ -68,39 +88,3 @@ jobs: -H 'Content-type: application/json' \ --data "{\"text\":\":x: *Ghost Guild CI failed* on \`${{ github.ref_name }}\`\nCommit: ${{ github.sha }}\n${{ github.server_url }}/${{ github.repository }}/actions\"}" - visual: - runs-on: ubuntu-latest - needs: vitest - continue-on-error: true - services: - mongo: - image: mongo:7 - ports: - - 27017:27017 - env: - MONGODB_URI: mongodb://localhost:27017/ghostguild-test - JWT_SECRET: ci-test-jwt-secret - NUXT_PUBLIC_COMING_SOON: 'false' - NODE_ENV: development - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 22 - cache: npm - - run: npm ci - - run: npx playwright install --with-deps chromium - - run: npm run build - - name: Start server - run: node .output/server/index.mjs & - env: - PORT: 3000 - - name: Wait for server - run: timeout 30 sh -c 'until curl -sf http://localhost:3000; do sleep 1; done' - - run: npx playwright test e2e/visual/ - - uses: actions/upload-artifact@v4 - if: failure() - with: - name: visual-diffs - path: e2e/test-results/ - retention-days: 7 diff --git a/app/assets/css/main.css b/app/assets/css/main.css index 4167651..9ee189f 100644 --- a/app/assets/css/main.css +++ b/app/assets/css/main.css @@ -27,7 +27,10 @@ --text: #2a2015; --text-bright: #1a1008; --text-dim: #5a5040; - --text-faint: #746a58; + /* Darkened from #746a58 (4.01:1 on --surface, fails WCAG AA) to #665c4b + (4.94:1 on --surface, 5.13:1 on --bg). Stays visually quieter than + --text-dim (5.80:1) while meeting AA for small text. */ + --text-faint: #665c4b; --parch: #2a2015; --parch-hover: #3a3025; --parch-text: #ede4d0; diff --git a/app/components/BoardPostCard.vue b/app/components/BoardPostCard.vue index 97067e9..a79a535 100644 --- a/app/components/BoardPostCard.vue +++ b/app/components/BoardPostCard.vue @@ -178,7 +178,8 @@ const slackLinks = computed(() => { font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; - color: var(--text-faint); + /* --text-faint fails WCAG AA (4.01:1) on the cream card bg */ + color: var(--text-dim); } .post-actions { @@ -233,7 +234,8 @@ const slackLinks = computed(() => { font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; - color: var(--text-faint); + /* --text-faint fails WCAG AA (4.01:1) on the cream card bg */ + color: var(--text-dim); margin-bottom: 2px; } .block-text { @@ -244,7 +246,8 @@ const slackLinks = computed(() => { .post-note { font-size: 11px; - color: var(--text-faint); + /* --text-faint fails WCAG AA (4.01:1) on the cream card bg */ + color: var(--text-dim); font-style: italic; margin: 8px 0; white-space: pre-wrap; @@ -293,7 +296,8 @@ const slackLinks = computed(() => { align-items: center; justify-content: center; font-size: 10px; - color: var(--text-faint); + /* --text-faint fails WCAG AA (4.01:1) on the cream card bg */ + color: var(--text-dim); font-family: "Commit Mono", monospace; } .author-name { @@ -308,7 +312,8 @@ const slackLinks = computed(() => { } .slack-handle { font-size: 11px; - color: var(--text-faint); + /* --text-faint fails WCAG AA (4.01:1) on the cream card bg */ + color: var(--text-dim); font-family: "Commit Mono", monospace; background: transparent; border: none; diff --git a/app/components/ImageUpload.vue b/app/components/ImageUpload.vue index bd8a87e..7db4306 100644 --- a/app/components/ImageUpload.vue +++ b/app/components/ImageUpload.vue @@ -77,12 +77,7 @@ @@ -225,3 +220,16 @@ const updateAltText = (altText) => { }); }; + + diff --git a/app/config/memberStatus.js b/app/config/memberStatus.js new file mode 100644 index 0000000..04850e8 --- /dev/null +++ b/app/config/memberStatus.js @@ -0,0 +1,8 @@ +export const STATUS_LABELS = { + active: "Active", + pending_payment: "Payment setup incomplete", + suspended: "Paused", + cancelled: "Closed", +}; + +export const statusLabel = (s) => STATUS_LABELS[s] || "Pending"; diff --git a/app/middleware/coming-soon.global.js b/app/middleware/coming-soon.global.js index c1ee747..d2433f8 100644 --- a/app/middleware/coming-soon.global.js +++ b/app/middleware/coming-soon.global.js @@ -21,6 +21,15 @@ export default defineNuxtRouteMiddleware(async (to, from) => { return; } + // Logged-in admins bypass coming-soon (and see the public site + their dashboard) + try { + const headers = import.meta.server ? useRequestHeaders(["cookie"]) : undefined; + const member = await $fetch("/api/auth/member", { headers }); + if (member?.role === "admin") return; + } catch { + // Not authenticated — fall through to redirect + } + // Redirect all other routes to coming-soon return navigateTo("/coming-soon"); }); diff --git a/app/pages/admin/members/[id].vue b/app/pages/admin/members/[id].vue index 567caf9..e082be7 100644 --- a/app/pages/admin/members/[id].vue +++ b/app/pages/admin/members/[id].vue @@ -63,10 +63,11 @@