Skip to content

Commit

Permalink
Adding photos from sites and better rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
datajohnson committed Sep 13, 2024
1 parent f1e73d5 commit 09f70b6
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 79 deletions.
26 changes: 26 additions & 0 deletions src/api/routes/photo-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,32 @@ photoRouter.get(
}
);

photoRouter.get(
'/:id/file/download',
[check('id').notEmpty().isUUID()],
async (req: Request, res: Response) => {
const errors = validationResult(req);

if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}

await photoService
.getFileById(req.params.id)
.then((photo) => {
if (photo && photo.file) {
return res.contentType('image/jpg').send(photo.file);
}

return res.status(404).send('Photo not found');
})
.catch((err) => {
console.error(err);
return res.status(404).send('Photo not found');
});
}
);

photoRouter.get(
'/:id/thumbfile',
[check('id').notEmpty().isUUID()],
Expand Down
35 changes: 34 additions & 1 deletion src/api/routes/place-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@ import {
matchedData,
} from 'express-validator';
import fs from 'fs';
import multer from 'multer';
import { create } from 'handlebars';
import handlebarsHelpers from '../utils/handlebars-helpers';

import { API_PORT, DB_CONFIG } from '../config';
import { PlaceService } from '../services';
import { PhotoService, PlaceService } from '../services';
import { ReturnValidationErrors } from '../middleware';
import { authorize } from '../middleware/authorization';
import { Place, User, UserRoles } from '../models';
import PlacesController from '../controllers/places-controller';
import { PlacePolicy } from '../policies';
import { generatePDF } from '../utils/pdf-generator';
import { createThumbnail } from '../utils/image';

const placeService = new PlaceService(DB_CONFIG);
const PAGE_SIZE = 10;
Expand Down Expand Up @@ -218,6 +220,37 @@ placeRouter.post(
}
);

placeRouter.post(
'/:id/photo',
authorize([
UserRoles.SITE_ADMIN,
UserRoles.SITE_EDITOR,
UserRoles.ADMINISTRATOR,
]),
multer().single('file'),
async (req: Request, res: Response) => {
try {
const { id } = req.params;

const ThumbFile = await createThumbnail(req.file.buffer);
const body = {
File: req.file.buffer,
ThumbFile,
...req.body,
placeId: id,
dateCreated: new Date(),
};

const photoService = new PhotoService(DB_CONFIG);
photoService.addPhoto(body);

return res.json({ data: 'success' });
} catch (err) {
return res.json({ data: 'failuer', error: err });
}
}
);

placeRouter.patch(
'/:id',
authorize([UserRoles.SITE_ADMIN, UserRoles.ADMINISTRATOR]),
Expand Down
13 changes: 13 additions & 0 deletions src/web/src/apis/places-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,17 @@ export default {
return Promise.reject(error);
});
},
uploadPhoto(id, data) {
return http
.post(`${placeUrl}/${id}/photo`, data, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
.then((response) => response.data)
.catch((error) => {
console.error(error);
return Promise.reject(error);
});
},
};
205 changes: 127 additions & 78 deletions src/web/src/components/Sites/site-forms/Photos.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,84 +39,120 @@
<v-col
v-for="(item, index) in photos"
:key="`photo-${index + 1}`"
cols="6"
cols="12"
md="6"
>
<v-row>
<v-col cols="10">
<img
class="center-img"
max-width="128"
<v-card>
<div style="width: 100%; overflow-x: hidden">
<v-img
v-if="item.img"
height="250px"
:src="item.img"
placeholder="No image selected"
aspect-ratio=".5"
/>
<v-img
v-else
height="250px"
:src="makeThumbnailUrl(item)"
/>
</v-col>
<v-col cols="2">
<v-btn
color="warning"
x-small
fab
title="Remove"
class="my-0 float-right"
</div>
<v-divider />
<v-card-text>
<v-file-input
v-if="isEditing"
v-model="item.file"
:id="`fi-${index}`"
label="Upload image"
prepend-inner-icon="mdi-camera"
prepend-icon=""
accept="image/*"
dense
outlined
background-color="white"
@change="onFileSelection($event, index)"
/>

<v-text-field
v-model="item.featureName"
label="Feature name"
dense
outlined
background-color="white"
:readonly="!isEditing"
/>

<v-text-field
v-model="item.caption"
label="Caption"
dense
outlined
background-color="white"
:readonly="!isEditing"
/>

<v-text-field
v-model="item.comments"
label="Comments"
dense
outlined
background-color="white"
:readonly="!isEditing"
/>

<v-text-field
v-model="item.creditLine"
label="Credit line"
dense
outlined
background-color="white"
:readonly="!isEditing"
@click="removePhoto(index)"
>
<v-icon>mdi-close</v-icon>
</v-btn>
</v-col>
</v-row>
<v-text-field
v-model="item.featureName"
label="Feature name"
dense
outlined
background-color="white"
:readonly="!isEditing"
/>

<v-text-field
v-model="item.caption"
label="Caption"
dense
outlined
background-color="white"
:readonly="!isEditing"
/>

<v-text-field
v-model="item.comments"
label="Comments"
dense
outlined
background-color="white"
:readonly="!isEditing"
/>

<v-text-field
v-model="item.creditLine"
label="Credit line"
dense
outlined
background-color="white"
:readonly="!isEditing"
/>

<v-text-field
v-model="item.location"
label="Location"
dense
outlined
background-color="white"
:readonly="!isEditing"
/>
<v-file-input
:id="`fi-${index}`"
label="Upload image"
prepend-icon="mdi-camera"
accept="image/*"
dense
outlined
background-color="white"
@change="onFileSelection($event, index)"
/>
/>

<v-text-field
v-model="item.location"
label="Location"
dense
outlined
background-color="white"
:readonly="!isEditing"
/>

<div class="d-flex">
<v-btn
color="primary"
small
title="Download"
class="my-0 mr-3"
@click="downloadPhoto(item)"
>
<v-icon>mdi-download</v-icon>
</v-btn>
<v-btn
color="info"
small
title="open"
class="my-0 mr-3"
@click="openPhotoPage(item)"
>
<v-icon>mdi-open-in-new</v-icon>
</v-btn>

<v-spacer />

<!-- <v-btn
v-if="isEditing"
color="warning"
small
title="Remove"
class="my-0"
@click="removePhoto(index)"
>
<v-icon>mdi-delete</v-icon>
</v-btn> -->
</div>
</v-card-text>
</v-card>
</v-col>
</v-row>
</v-card-text>
Expand Down Expand Up @@ -151,6 +187,7 @@ import axios from 'axios';
import store from '@/store';
import { PLACE_URL, PHOTO_URL } from '@/urls';
import { mapActions } from 'vuex';
/* Important**, field data that was not found on the swaggerhub api docs provided was assumed to be in development, hence, some placeholder variables were created. */
export default {
Expand Down Expand Up @@ -185,6 +222,7 @@ export default {
.catch((error) => console.error(error));
},
methods: {
...mapActions('places', ['savePhotos']),
addPhoto() {
this.photos.push({});
},
Expand All @@ -194,20 +232,31 @@ export default {
onFileSelection(event, i) {
if (event) {
//this.fields.photos[i].img = URL.createObjectURL(event.target.files[0]);
this.fields.photos[i].img = URL.createObjectURL(event);
this.photos[i].img = URL.createObjectURL(event);
} else {
this.fields.photos[i].img = null;
this.photos[i].img = null;
}
},
save() {
console.error('Not implemented');
async save() {
await this.savePhotos(this.photos);
},
makeThumbnailUrl(photo) {
return `${PHOTO_URL}/${photo.rowId}/thumbfile`;
},
makePhotoUrl(photo) {
return `${PHOTO_URL}/${photo.rowId}/thumbfile`;
},
downloadPhoto(item) {
console.log(item);
window.open(`${PHOTO_URL}/${item.rowId}/file/download`);
},
openPhotoPage(item) {
localStorage.setItem('currentRowId', item.rowId);
this.$store.commit('photos/setRowId', item.rowId);
window.open(`/photos/view`);
},
},
};
</script>
Expand Down
Loading

0 comments on commit 09f70b6

Please sign in to comment.