Compare commits

...

3 Commits

Author SHA1 Message Date
Roman Krček
58f440062e Add gitea workflows
Some checks failed
Build Docker image / build (push) Has been cancelled
2025-05-17 14:04:01 +02:00
Roman Krček
05ad84c809 Added Dockerfile 2025-05-17 14:01:01 +02:00
Roman Krček
5d647112b3 Basic functionality 2025-05-17 13:41:47 +02:00
8 changed files with 438 additions and 117 deletions

2
.dockerignore Normal file
View File

@@ -0,0 +1,2 @@
node_modules/
.svelte-kit/

View File

@@ -0,0 +1,56 @@
name: Build Docker image
run-name: ${{ gitea.actor }} is running the CI pipeline
on:
push:
branches:
- main
schedule:
- cron: "0 22 * * 0" # sunday 22:00
jobs:
build:
runs-on: ubuntu-latest
needs: test
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Get date for image label
id: date
run: echo "::set-output name=date::$(date +'%Y-%m-%d')"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver: docker-container
- name: Login to Docker Registry
uses: docker/login-action@v3
with:
registry: git.orebolt.cz
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Build and push image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: "${{ vars.DOCKER_IMAGE }}:latest,${{ vars.DOCKER_IMAGE }}:${{ steps.date.outputs.date }}"
platforms: linux/amd64
cache-to: "mode=max,image-manifest=true,oci-mediatypes=true,type=registry,ref=${{ vars.DOCKER_IMAGE }}:cache"
cache-from: "mode=max,image-manifest=true,oci-mediatypes=true,type=registry,ref=${{ vars.DOCKER_IMAGE }}:cache"
labels: |
org.opencontainers.image.created=${{ steps.date.outputs.date }}
org.opencontainers.image.authors=Roman Krček
org.opencontainers.image.source=${{ env.GITHUB_REPOSITORY }}
org.opencontainers.image.revision=${{ env.GITHUB_SHA }}
org.opencontainers.image.vendor=Orebolt.cz
org.opencontainers.image.ref.name=${{ env.GITHUB_REF }}
org.opencontainers.image.title=ESN Code Scanner App
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@0.24.0
with:
image-ref: '${{ vars.DOCKER_IMAGE }}:latest'
format: 'table'

19
Dockerfile Normal file
View File

@@ -0,0 +1,19 @@
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json ./
COPY package-lock.json ./
RUN npm install
COPY . ./
RUN npm run build
RUN npm prune --production
FROM node:22-alpine
USER node:node
WORKDIR /app
COPY --from=builder --chown=node:node /app/build build/
COPY --from=builder --chown=node:node /app/node_modules node_modules/
COPY package.json .
EXPOSE 3000
ENV NODE_ENV=production
CMD [ "node", "build" ]

337
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -14,11 +14,11 @@
"lint": "prettier --check ." "lint": "prettier --check ."
}, },
"devDependencies": { "devDependencies": {
"@sveltejs/adapter-auto": "^6.0.0",
"@sveltejs/kit": "^2.16.0", "@sveltejs/kit": "^2.16.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0", "@sveltejs/vite-plugin-svelte": "^5.0.0",
"@tailwindcss/typography": "^0.5.15", "@tailwindcss/typography": "^0.5.15",
"@tailwindcss/vite": "^4.0.0", "@tailwindcss/vite": "^4.0.0",
"html5-qrcode": "^2.3.8",
"prettier": "^3.4.2", "prettier": "^3.4.2",
"prettier-plugin-svelte": "^3.3.3", "prettier-plugin-svelte": "^3.3.3",
"prettier-plugin-tailwindcss": "^0.6.11", "prettier-plugin-tailwindcss": "^0.6.11",
@@ -27,5 +27,8 @@
"tailwindcss": "^4.0.0", "tailwindcss": "^4.0.0",
"typescript": "^5.0.0", "typescript": "^5.0.0",
"vite": "^6.2.6" "vite": "^6.2.6"
},
"dependencies": {
"@sveltejs/adapter-node": "^5.2.12"
} }
} }

View File

@@ -1,2 +1,68 @@
<h1>Welcome to SvelteKit</h1> <script>
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p> import { onMount, tick } from 'svelte';
import QRScanner from './QRScanner.svelte';
let scanned_id = $state('');
let scan_user = $state('Roman');
let scan_data = $state({});
let ticket_state = $state('not_scanned');
onMount(() => {reset_scan_data()});
function reset_scan_data() {
ticket_state = 'unknown';
scan_data = {
id: 0,
created_at: 'none',
name: 'none',
surname: 'none',
email: 'none@esnvutbrno.cz',
uuid: 'none',
scanned: 'none',
scanned_at: 'none',
event_name: 'none',
scanned_by: 'none'
};
}
$effect(() => {
if (scan_data.scanned === true) {
ticket_state = 'Already scanned';
} else if (scan_data.scanned === false) {
ticket_state = 'Good to go in 2';
console.log(scan_data.scanned);
} else {
ticket_state = 'Ticket invalid';
}
});
$effect(() => {
console.log('Message updated:', scanned_id);
reset_scan_data();
fetch('https://n8n.orebolt.cz/webhook/9d32752c-47c9-46db-be6d-f473e97a7c25', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ scanned_id, scan_user })
})
.then((response) => response.json())
.then((data) => {
scan_data = data;
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
ticket_state = "Ticket invalid";
});
});
</script>
<QRScanner bind:message={scanned_id} />
<p>CODE: {scanned_id}</p>
<p>Name: {scan_data.name} {scan_data.surname}</p>
<p>State: {ticket_state}</p>
<p>Event: {scan_data.event_name}</p>

View File

@@ -0,0 +1,64 @@
<script lang="ts">
import { onMount } from 'svelte';
import {
Html5QrcodeScanner,
type Html5QrcodeResult,
Html5QrcodeScanType,
Html5QrcodeSupportedFormats,
Html5QrcodeScannerState,
} from 'html5-qrcode';
let width: number = 300;
let height: number = 300;
let { message = $bindable() } = $props();
function onScanSuccess(decodedText: string, decodedResult: Html5QrcodeResult): void {
//console.log(`Code scanned = ${decodedText}`);
message = decodedText;
}
// usually better to ignore and keep scanning
function onScanFailure(message: string) {
//console.log(`Code scan error = ${message}`);
}
let scanner: Html5QrcodeScanner;
onMount(() => {
scanner = new Html5QrcodeScanner(
'qr-scanner',
{
fps: 5,
qrbox: { width, height },
aspectRatio: 1,
supportedScanTypes: [Html5QrcodeScanType.SCAN_TYPE_CAMERA],
formatsToSupport: [Html5QrcodeSupportedFormats.QR_CODE],
},
false // non-verbose
);
scanner.render(onScanSuccess, onScanFailure);
});
</script>
<div id="qr-scanner" class="w-full max-w-sm bg-slate-700 rounded-lg overflow-hidden"></div>
<style>
/* Hide unwanted icons */
#qr-scanner :global(img[alt='Info icon']),
#qr-scanner :global(img[alt='Camera based scan']) {
display: none;
}
/* Change camera permission button text */
#qr-scanner :global(#html5-qrcode-button-camera-permission) {
visibility: hidden;
}
#qr-scanner :global(#html5-qrcode-button-camera-permission::after) {
position: absolute;
inset: auto 0 0;
display: block;
content: 'Allow camera access';
visibility: visible;
padding: 10px 0;
}
</style>

View File

@@ -1,4 +1,4 @@
import adapter from '@sveltejs/adapter-auto'; import adapter from '@sveltejs/adapter-node';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */