Skip to content

Commit

Permalink
2 / Controllers, Services, Routes, Lifecycle hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
cyp3rius committed Oct 21, 2024
1 parent 02fc2cb commit 974af09
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 7 deletions.
Binary file modified .tmp/data.db
Binary file not shown.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@strapi/plugin-graphql": "^5.1.0",
"@strapi/plugin-users-permissions": "5.1.0",
"@strapi/strapi": "5.1.0",
"@strapi/utils": "5.1.0",
"better-sqlite3": "11.3.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
Expand Down
8 changes: 7 additions & 1 deletion src/api/booking/content-types/booking/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@
"displayName": "Booking"
},
"options": {
"draftAndPublish": true
"draftAndPublish": false
},
"pluginOptions": {},
"attributes": {
"ref_number": {
"type": "string",
"unique": true,
"required": true,
"configurable": false
},
"from": {
"type": "datetime",
"required": true
Expand Down
98 changes: 96 additions & 2 deletions src/api/booking/controllers/booking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,100 @@
* booking controller
*/

import { factories } from '@strapi/strapi'
import { factories } from '@strapi/strapi';
import { errors } from '@strapi/utils';

export default factories.createCoreController('api::booking.booking');
export default factories.createCoreController('api::booking.booking', ({ strapi }) => ({
// Validate the availability of a car within the following dates
async validateAvailability(ctx) {
const sanitizedQuery = await this.sanitizeQuery(ctx);

const { from, to, car } = sanitizedQuery;
try {
return strapi.service('api::booking.booking').validateAvailability(from, to, car);
} catch (err) {
throw new errors.HttpError('Not available');
}
},

// Extend the create booking method
async create(ctx, next) {

// Validate availablity
await this.validateAvailability(ctx, next);

// Before creation generate reference number
const refNumber = strapi.service('api::booking.booking').generateReferenceNumber();

const { car, ...restBody } = ctx.request.body.data;

const nextCtx = {
...ctx,
query: {}, // Clean the query to avoid any conflict
request: {
...ctx.request,
body: {
...ctx.request.body,
data: {
...restBody,
ref_number: refNumber,
}
},
},
};

console.log(nextCtx.request.body)

// Call the native create booking method
const { data } = await super.create(nextCtx);
const { documentId } = data;

// Link booking to car
const bookedCar = await strapi.service('api::booking.booking').linkBookingToCar(documentId, car);

// Link booking to user
const customer = await strapi.service('api::booking.booking').linkBookingToUser(documentId, ctx.state.user.documentId);

console.log('bookedCar', bookedCar);
console.log('customer', customer);
const { ref_number } = data;

console.log('data', data);

// try {
// // Send a confirmation email
// await strapi.plugins['email'].services.email.send({
// to: ctx.state.user.email,
// subject: `[#${ref_number}]Booking confirmation`,
// text: `Your booking number #${ref_number} has been confirmed`
// });
// } catch (err) {
// console.error('Error sending email', err);
// }

return {
data: {
...data,
car: bookedCar,
customer,
},
};
},

// Method 3: Replacing a core action with proper sanitization
// async find(ctx) {
// // validateQuery (optional)
// // to throw an error on query params that are invalid or the user does not have access to
// await this.validateQuery(ctx);

// // sanitizeQuery to remove any query params that are invalid or the user does not have access to
// // It is strongly recommended to use sanitizeQuery even if validateQuery is used
// const sanitizedQueryParams = await this.sanitizeQuery(ctx);
// const { results, pagination } = await strapi.service('api::restaurant.restaurant').find(sanitizedQueryParams);

// // sanitizeOutput to ensure the user does not receive any data they do not have access to
// const sanitizedResults = await this.sanitizeOutput(results, ctx);

// return this.transformResponse(sanitizedResults, { pagination });
// }
}));
4 changes: 3 additions & 1 deletion src/api/booking/routes/booking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@

import { factories } from '@strapi/strapi';

export default factories.createCoreRouter('api::booking.booking');


export default factories.createCoreRouter('api::booking.booking');
13 changes: 13 additions & 0 deletions src/api/booking/routes/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

export default {
routes: [
{
method: 'POST',
path: '/bookings/validate-availability',
handler: 'api::booking.booking.validateAvailability',
config: {
auth: false,
},
},
],
};
56 changes: 54 additions & 2 deletions src/api/booking/services/booking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,58 @@
* booking service
*/

import { factories } from '@strapi/strapi';
import { factories, type Data } from '@strapi/strapi';

export default factories.createCoreService('api::booking.booking');
export default factories.createCoreService('api::booking.booking', ({ strapi }) => ({

// Generate unique reference number
generateReferenceNumber(): string {
return Date.now().toString(36).toUpperCase();
},


// Validate the availability of a car within the following dates
async validateAvailability(from: string, to: string, id: Data.DocumentID): Promise<boolean> {
const bookings = await strapi.documents('api::booking.booking').findMany({
filters: {
car: {
documentId: id
},
from: { $lt: new Date(to) },
to: { $gt: new Date(from) }
},
});

console.log('bookings', bookings);

return !bookings.length;
},

// Link booking to car
async linkBookingToCar(booking: Data.DocumentID, car: Data.DocumentID): Promise<unknown> {
// Link booking to car
return strapi.documents('api::car.car').update({
documentId: car,
data: {
bookings: {
connect: [booking],
},
},
status: 'published',
});
},

// Link booking to user
async linkBookingToUser(booking: Data.DocumentID, user: Data.DocumentID): Promise<unknown> {
return strapi.documents('plugin::users-permissions.user').update({
documentId: user,
data: {
bookings: {
connect: [booking],
},
},
status: 'published',
});
},

}));
5 changes: 4 additions & 1 deletion types/generated/contentTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ export interface ApiBookingBooking extends Struct.CollectionTypeSchema {
displayName: 'Booking';
};
options: {
draftAndPublish: true;
draftAndPublish: false;
};
attributes: {
ref_number: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.Unique;
from: Schema.Attribute.DateTime & Schema.Attribute.Required;
to: Schema.Attribute.DateTime;
car: Schema.Attribute.Relation<'manyToOne', 'api::car.car'>;
Expand Down

0 comments on commit 974af09

Please sign in to comment.