Skip to content

Commit 2fc8baa

Browse files
committed
feat: store images on DB
1 parent 2b50dc8 commit 2fc8baa

File tree

17 files changed

+105
-179
lines changed

17 files changed

+105
-179
lines changed

Makefile

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,32 +20,18 @@ dev:
2020
@echo "Building website image..."
2121
@docker build --pull --no-cache -t fraguinha/a50passos.com:latest src/website
2222

23-
@echo "Building assets image..."
24-
@docker build --pull --no-cache -t fraguinha/a50passos.com-assets:latest -f src/website/Dockerfile.assets .
25-
2623
@echo "Tagging website image..."
2724
@docker tag fraguinha/a50passos.com localhost:10000/fraguinha/a50passos.com:latest
2825

29-
@echo "Tagging assets image..."
30-
@docker tag fraguinha/a50passos.com-assets localhost:10000/fraguinha/a50passos.com-assets:latest
31-
3226
@echo "Pushing website image..."
3327
@docker push localhost:10000/fraguinha/a50passos.com:latest
3428

35-
@echo "Pushing assets image..."
36-
@docker push localhost:10000/fraguinha/a50passos.com-assets:latest
37-
3829
@echo "Capturing website image digest..."; \
3930
WEBSITE_SHA=$$(docker inspect --format='{{index .RepoDigests 0}}' fraguinha/a50passos.com:latest | cut -d'@' -f2); \
4031
echo "Website SHA: $$WEBSITE_SHA"; \
4132
\
42-
echo "Capturing assets image digest..."; \
43-
ASSETS_SHA=$$(docker inspect --format='{{index .RepoDigests 0}}' fraguinha/a50passos.com-assets:latest | cut -d'@' -f2); \
44-
echo "Assets SHA: $$ASSETS_SHA"; \
45-
\
4633
echo "Patching kubernetes manifests with SHA digests..."; \
4734
sed -i '' "s|a50passos.com:latest|a50passos.com:latest@$$WEBSITE_SHA|g" local/website.yml; \
48-
sed -i '' "s|a50passos.com-assets:latest|a50passos.com-assets:latest@$$ASSETS_SHA|g" local/website.yml; \
4935
\
5036
echo "Applying kubernetes manifests..."; \
5137
kubectl apply -k local/
@@ -71,4 +57,4 @@ clean:
7157

7258
mongo-shell:
7359
@echo "Connecting to MongoDB shell..."
74-
@docker exec -it mongodb mongosh
60+
@docker exec -it mongodb mongosh

k8s/website.yml

Lines changed: 1 addition & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -23,31 +23,6 @@ spec:
2323
alphabetical:
2424
order: asc
2525
---
26-
apiVersion: image.toolkit.fluxcd.io/v1
27-
kind: ImageRepository
28-
metadata:
29-
name: a50passos-website-assets-image
30-
namespace: flux-system
31-
spec:
32-
image: fraguinha/a50passos.com-assets
33-
interval: 1m0s
34-
---
35-
apiVersion: image.toolkit.fluxcd.io/v1
36-
kind: ImagePolicy
37-
metadata:
38-
name: a50passos-website-assets-policy
39-
namespace: flux-system
40-
spec:
41-
digestReflectionPolicy: Always
42-
interval: 1m0s
43-
imageRepositoryRef:
44-
name: a50passos-website-assets-image
45-
filterTags:
46-
pattern: '^latest$'
47-
policy:
48-
alphabetical:
49-
order: asc
50-
---
5126
apiVersion: apps/v1
5227
kind: Deployment
5328
metadata:
@@ -63,20 +38,6 @@ spec:
6338
labels:
6439
app: website
6540
spec:
66-
initContainers:
67-
- name: create-uploads-dir
68-
image: busybox
69-
command: ['sh', '-c', 'mkdir -p /app/dist/public/images/uploads && chmod -R 755 /app/dist/public/images/uploads']
70-
volumeMounts:
71-
- name: images
72-
mountPath: /app/dist/public/images
73-
- name: copy-image-assets
74-
image: fraguinha/a50passos.com-assets:latest@sha256:0df2dfb11aedd0be1735e61a9724f475730fd2a05892fd2883a485b97340204a # {"$imagepolicy": "a50passos:a50passos-website-assets-policy"}
75-
imagePullPolicy: Always
76-
command: ['sh', '-c', 'cp -r /assets/* /app/dist/public/images/']
77-
volumeMounts:
78-
- name: images
79-
mountPath: /app/dist/public/images
8041
containers:
8142
- name: website
8243
image: fraguinha/a50passos.com:latest@sha256:733675b0a356cc9ca9273893b7c211d25f6a86e9d4de75f0a967ab4c801fe8cb # {"$imagepolicy": "a50passos:a50passos-website-policy"}
@@ -100,13 +61,6 @@ spec:
10061
secretKeyRef:
10162
name: a50passos-secrets
10263
key: SESSION_SECRET
103-
volumeMounts:
104-
- name: images
105-
mountPath: /app/dist/public/images
106-
volumes:
107-
- name: images
108-
persistentVolumeClaim:
109-
claimName: a50passos-images-pvc
11064
---
11165
apiVersion: v1
11266
kind: Service
@@ -117,20 +71,4 @@ spec:
11771
selector:
11872
app: website
11973
ports:
120-
- port: 8080
121-
targetPort: 8080
122-
---
123-
apiVersion: v1
124-
kind: PersistentVolumeClaim
125-
metadata:
126-
name: a50passos-images-pvc
127-
namespace: a50passos
128-
annotations:
129-
recurring-job.longhorn.io/default: enabled
130-
spec:
131-
accessModes:
132-
- ReadWriteMany
133-
storageClassName: longhorn
134-
resources:
135-
requests:
136-
storage: 1Gi
74+
- port: 8080

local/website.yml

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,6 @@ spec:
1313
labels:
1414
app: website
1515
spec:
16-
initContainers:
17-
- name: create-uploads-dir
18-
image: busybox
19-
command: ['sh', '-c', 'mkdir -p /app/dist/public/images/uploads && chmod -R 755 /app/dist/public/images/uploads']
20-
volumeMounts:
21-
- name: images
22-
mountPath: /app/dist/public/images
23-
- name: copy-image-assets
24-
image: k3d-a50passos-registry:10000/fraguinha/a50passos.com-assets:latest
25-
imagePullPolicy: Always
26-
command: ['sh', '-c', 'cp -r /assets/* /app/dist/public/images/']
27-
volumeMounts:
28-
- name: images
29-
mountPath: /app/dist/public/images
3016
containers:
3117
- name: website
3218
image: k3d-a50passos-registry:10000/fraguinha/a50passos.com:latest
@@ -50,13 +36,6 @@ spec:
5036
secretKeyRef:
5137
name: a50passos-secrets
5238
key: SESSION_SECRET
53-
volumeMounts:
54-
- name: images
55-
mountPath: /app/dist/public/images
56-
volumes:
57-
- name: images
58-
persistentVolumeClaim:
59-
claimName: a50passos-images-pvc
6039
---
6140
apiVersion: v1
6241
kind: Service
@@ -67,17 +46,4 @@ spec:
6746
selector:
6847
app: website
6948
ports:
70-
- port: 8080
71-
targetPort: 8080
72-
---
73-
apiVersion: v1
74-
kind: PersistentVolumeClaim
75-
metadata:
76-
name: a50passos-images-pvc
77-
namespace: a50passos
78-
spec:
79-
accessModes:
80-
- ReadWriteOnce
81-
resources:
82-
requests:
83-
storage: 1Gi
49+
- port: 8080

src/website/Dockerfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ RUN npm ci --verbose
1010
COPY . .
1111

1212
RUN npm run deploy
13-
RUN rm -rf /app/dist/public/images
1413

1514
FROM node:22-slim
1615

src/website/Dockerfile.assets

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/website/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"start": "node dist/server.js",
99
"build": "tsc",
1010
"views": "cp -r src/views dist",
11-
"public": "cp -r src/public dist; mkdir -p dist/public/images/uploads",
11+
"public": "cp -r src/public dist",
1212
"dist": "npm run views; npm run public",
1313
"deploy": "npm run build; npm run dist",
1414
"clean": "rm -rf dist",

src/website/src/api/api.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import express from 'express'
22
import admin from './routes/admin.js'
33
import auth from './routes/auth.js'
4+
import images from './routes/images.js'
45

56
const router = express.Router()
67

78
router.use('/admin', admin)
89
router.use('/auth', auth)
10+
router.use('/images', images)
911

1012
export default router

src/website/src/api/routes/admin.ts

Lines changed: 20 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
import express from 'express'
2-
import fs from 'fs'
3-
import path from 'path'
42
import authenticator from '../../lib/middleware/authentication.js'
53
import rateLimiter from '../../lib/middleware/rate-limiter.js'
64
import {
7-
dist,
8-
imagesDirectory,
95
imageSizeBig,
106
imageSizeSmall,
11-
uploadDirectory,
127
} from '../../lib/constants/constants.js'
138
import House from '../../models/house-model.js'
149
import Meta from '../../models/meta-model.js'
10+
import TemporaryPhoto from '../../models/temporary-photo-model.js'
1511
import sharp from 'sharp'
1612
import uploader from '../../lib/middleware/uploader.js'
1713

@@ -40,43 +36,40 @@ router.post(
4036
return res.status(400).redirect('/')
4137
}
4238

43-
let photoCounter = 1
44-
4539
for (const photo of files) {
46-
await sharp(photo.buffer)
40+
const buffer = await sharp(photo.buffer)
4741
.resize({
4842
width: imageSizeBig,
4943
height: imageSizeSmall,
5044
})
5145
.rotate(90)
5246
.webp({ quality: 80 })
53-
.toFile(
54-
path.join(dist, uploadDirectory, `/photo${photoCounter++}.webp`)
55-
)
47+
.toBuffer()
48+
49+
const temporaryPhoto = new TemporaryPhoto({
50+
data: buffer,
51+
contentType: 'image/webp',
52+
})
53+
await temporaryPhoto.save()
5654
}
5755

5856
res.status(201).redirect('/')
5957
}
6058
)
6159

6260
router.post('/clearPhotos', rateLimiter, authenticator, async (_req, res) => {
63-
fs.readdir(path.join(dist, uploadDirectory), (_err, files) => {
64-
for (const file of files) {
65-
fs.unlinkSync(path.join(dist, uploadDirectory, file))
66-
}
67-
68-
res.status(200).redirect('/')
69-
})
61+
await TemporaryPhoto.deleteMany({}).exec()
62+
res.status(200).redirect('/')
7063
})
7164

7265
router.post('/addHouse', rateLimiter, authenticator, async (req, res) => {
73-
let num_photos = fs.readdirSync(path.join(dist, uploadDirectory)).length
66+
const temporaryPhotos = await TemporaryPhoto.find().exec()
7467

75-
if (num_photos >= 1) {
68+
if (temporaryPhotos.length >= 1) {
7669
let id = req.body.id
7770

7871
if (!id) {
79-
id = Date.now()
72+
id = Date.now().toString()
8073
}
8174

8275
const house = new House({
@@ -94,19 +87,15 @@ router.post('/addHouse', rateLimiter, authenticator, async (req, res) => {
9487
dinningroom: !!req.body.dinningroom,
9588
balcony: !!req.body.balcony,
9689
gardin: !!req.body.gardin,
97-
photos: num_photos,
90+
photos: temporaryPhotos.length,
91+
images: temporaryPhotos.map((p) => ({
92+
data: p.data,
93+
contentType: p.contentType,
94+
})),
9895
})
9996

100-
fs.mkdirSync(path.join(dist, imagesDirectory, id))
101-
const files = fs.readdirSync(path.join(dist, uploadDirectory))
102-
for (const file of files) {
103-
fs.renameSync(
104-
path.join(dist, uploadDirectory, file),
105-
path.join(dist, imagesDirectory, id, file)
106-
)
107-
}
108-
10997
await house.save()
98+
await TemporaryPhoto.deleteMany({}).exec()
11099

111100
res.redirect('/')
112101
} else {
@@ -136,18 +125,7 @@ router.post('/toggleHouse', rateLimiter, authenticator, async (req, res) => {
136125
})
137126

138127
router.post('/removeHouse', rateLimiter, authenticator, async (req, res) => {
139-
const directory = path
140-
.join(dist, imagesDirectory, req.body.id)
141-
.replace(/^(\.\.(\/|\\|$))+/, '')
142-
143128
await House.deleteOne({ id: req.body.id }).exec()
144-
145-
const files = fs.readdirSync(directory)
146-
for (const file of files) {
147-
fs.unlinkSync(path.join(directory, file))
148-
}
149-
fs.rmdirSync(directory)
150-
151129
res.redirect('/')
152130
})
153131

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import express from 'express'
2+
import House from '../../models/house-model.js'
3+
import TemporaryPhoto from '../../models/temporary-photo-model.js'
4+
5+
const router = express.Router()
6+
7+
router.get('/temporary/:index', async (req, res) => {
8+
const index = parseInt(req.params.index) - 1
9+
const temporaryPhotos = await TemporaryPhoto.find().exec()
10+
if (temporaryPhotos && temporaryPhotos[index]) {
11+
res.contentType(temporaryPhotos[index].contentType)
12+
res.send(temporaryPhotos[index].data)
13+
} else {
14+
res.status(404).end()
15+
}
16+
})
17+
18+
router.get('/house/:id/:index', async (req, res) => {
19+
const index = parseInt(req.params.index) - 1
20+
const house = await House.findOne({ id: req.params.id }).exec()
21+
if (house && house.images && house.images[index]) {
22+
res.contentType(house.images[index].contentType)
23+
res.send(house.images[index].data)
24+
} else {
25+
res.status(404).end()
26+
}
27+
})
28+
29+
export default router

src/website/src/lib/constants/constants.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
import path from 'path'
22

3-
const dist = path.resolve('dist')
4-
5-
const imagesDirectory = '/public/images'
6-
const uploadDirectory = imagesDirectory + '/uploads'
7-
83
const numberItems = 9
94
const paginationNumber = 5
105

@@ -17,9 +12,6 @@ const ROOM = 1
1712
const APARTMENT = 2
1813

1914
export {
20-
dist,
21-
imagesDirectory,
22-
uploadDirectory,
2315
numberItems,
2416
paginationNumber,
2517
imageSizeSmall,

0 commit comments

Comments
 (0)