diff --git a/api/main_endpoints/models/Advertisement.js b/api/main_endpoints/models/Advertisement.js index b35e047f6..62e0d54ee 100644 --- a/api/main_endpoints/models/Advertisement.js +++ b/api/main_endpoints/models/Advertisement.js @@ -8,11 +8,13 @@ const AdvertisementSchema = new Schema( required: true, maxlength: [255, 'message must be at most 255 characters long'] }, - expireDate: { + expireAt: { type: Date, + default: undefined, + index: {expireAfterSeconds: 0}, // TTL only kicks in when expireAt is set } }, - { collection: 'Advertisements' } + { collection: 'Advertisements', timestamps: { createdAt: true } } ); module.exports = mongoose.model('Advertisement', AdvertisementSchema); diff --git a/api/main_endpoints/routes/Advertisement.js b/api/main_endpoints/routes/Advertisement.js index a726a992c..09bb7bb75 100644 --- a/api/main_endpoints/routes/Advertisement.js +++ b/api/main_endpoints/routes/Advertisement.js @@ -19,10 +19,12 @@ router.get('/', async (req, res) => { res.status(OK).send(items || {}); }) .catch(error => { + logger.error('/api/Advertisement/ had an error', error); res.sendStatus(BAD_REQUEST); }); }); + router.get('/getAllAdvertisements', async (req, res) => { if (!checkIfTokenSent(req)) { return res.sendStatus(FORBIDDEN); @@ -30,8 +32,10 @@ router.get('/getAllAdvertisements', async (req, res) => { return res.sendStatus(UNAUTHORIZED); } Advertisement.find() + .sort({ createdAt: -1 }) .then(items => res.status(OK).send(items)) .catch(error => { + logger.error('/api/Advertisement/getAllAdvertisements/ had an error', error); res.sendStatus(BAD_REQUEST); }); }); @@ -48,7 +52,7 @@ router.post('/createAdvertisement', async (req, res) => { const newAd = new Advertisement({ message: req.body.message, - expireDate: req.body.expireDate + expireAt: req.body.expireDate }); try { @@ -58,7 +62,7 @@ router.post('/createAdvertisement', async (req, res) => { action: AuditLogActions.CREATE_AD, details: { message: createdAd.message, - expireDate: createdAd.expireDate, + expireAt: createdAd.expireAt, advertisementId: createdAd._id } }).catch(logger.error); @@ -83,15 +87,9 @@ router.post('/deleteAdvertisement', async (req, res) => { } try { - const adToDelete = await Advertisement.findById(req.body._id); - - if (!adToDelete) { - return res.sendStatus(NOT_FOUND); - } - - const deleteResult = await Advertisement.deleteOne({_id: req.body._id}); + const deleteResult = await Advertisement.findOneAndDelete({ _id: req.body._id }); - if(deleteResult.deletedCount < 1) { + if(!deleteResult) { return res.sendStatus(NOT_FOUND); } @@ -100,8 +98,8 @@ router.post('/deleteAdvertisement', async (req, res) => { action: AuditLogActions.DELETE_AD, details: { deletedAd: { - id: adToDelete._id, - message: adToDelete.message, + id: deleteResult._id, + message: deleteResult.message, } } }).catch(logger.error); diff --git a/src/Pages/Advertisement/AdvertisementAdmin.js b/src/Pages/Advertisement/AdvertisementAdmin.js index 049f65087..12ef6c447 100644 --- a/src/Pages/Advertisement/AdvertisementAdmin.js +++ b/src/Pages/Advertisement/AdvertisementAdmin.js @@ -8,9 +8,8 @@ export default function AdvertisementAdmin() { const [ads, setAds] = useState([]); const [message, setMessage] = useState(''); - const [year, setYear] = useState(); - const [month, setMonth] = useState(); - const [day, setDay] = useState(); + const [expireDate, setExpireDate] = useState(); + const [expireButtonClicked, setExpiredButtonClicked] = useState(false); async function getAdsFromDB() { const adsFromDB = await getAds(user.token); @@ -19,54 +18,129 @@ export default function AdvertisementAdmin() { } } + function isExpired() { + if (!expireDate) { + return false; + } + const currDate = new Date(); + const expireDateObject = new Date(expireDate); + return expireDateObject < currDate; + } + async function createAdHandler() { - // make sure empty inputs are properly set as undefined if empty - if (year === '') { - setYear(undefined); + const newAd = { message }; + if (expireDate) { + const asDateObject = new Date(expireDate); + newAd.expireDate = asDateObject.toISOString(); } - if (month === '') { - setMonth(undefined); + // expireDate is a string so we need to turn into date object + await createAd(newAd, user.token); + + await getAdsFromDB(); + } + + function maybeRenderExpirationInput() { + if (!message) { + return null; } - if (day === '') { - setDay(undefined); + if (!expireButtonClicked) { + return ( + <> + + > + ); } + return ( + <> + { + setExpireDate(event.target.value); + }} + /> + + > + ); + } - let expireDate = new Date(year, month - 1, day); - if (isNaN(expireDate.getTime())) { - expireDate = undefined; + function getFormattedTime(maybeISOString = null) { + let date = new Date(); + if (maybeISOString) { + date = new Date(maybeISOString); } - await createAd({ - message, - expireDate, - }, user.token); - - await getAdsFromDB(); + return date.toLocaleString('en-US', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: 'numeric', + minute: '2-digit', + hour12: true, + timeZoneName: 'short', + }); } - async function deleteExpiredAds() { - const adsFromDB = await getAds(user.token); - if (!adsFromDB.error) { - const currentDate = new Date(); - const expiredAds = adsFromDB.responseData.filter(ad => { - if (ad.expireDate === undefined) return false; - return new Date(ad.expireDate) < currentDate; - }); - - for (const ad of expiredAds) { - await deleteAd(ad, user.token); - } + function maybeRenderCreateAdInputs() { + if (!message) { + return; } + return ( + <> + {message &&
| - Expiriation Date + Expiration Date | Delete @@ -156,12 +188,12 @@ export default function AdvertisementAdmin() { {ad.message} | - {ad.expireDate === undefined ? 'N/A' : ad.expireDate} + {ad.expireAt ? getFormattedTime(ad.expireAt) : '-'} |
|---|