image optimization. Image resizing client side, index added to db, pagination

This commit is contained in:
jackiettran
2025-12-30 20:23:32 -05:00
parent 3e31b9d08b
commit 807082eebf
25 changed files with 587 additions and 123 deletions

View File

@@ -0,0 +1,20 @@
'use strict';
/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
// Add index on latitude and longitude columns for faster geospatial queries
// This improves performance of the bounding box pre-filter used in radius searches
await queryInterface.addIndex('Items', ['latitude', 'longitude'], {
name: 'idx_items_lat_lng',
where: {
latitude: { [Sequelize.Op.ne]: null },
longitude: { [Sequelize.Op.ne]: null }
}
});
},
async down(queryInterface, Sequelize) {
await queryInterface.removeIndex('Items', 'idx_items_lat_lng');
}
};

View File

@@ -6,6 +6,28 @@ const { Op } = require("sequelize");
* Used to authorize signed URL requests for private content
*/
class S3OwnershipService {
/**
* Image size variant suffixes
*/
static SIZE_SUFFIXES = ["_th", "_md"];
/**
* Extract the base key from a variant key (strips _th or _md suffix)
* @param {string} key - S3 key like "messages/uuid_th.jpg" or "messages/uuid.jpg"
* @returns {string} - Base key like "messages/uuid.jpg"
*/
static getBaseKey(key) {
if (!key) return key;
for (const suffix of this.SIZE_SUFFIXES) {
// Match suffix before file extension (e.g., _th.jpg, _md.png)
const regex = new RegExp(`${suffix}(\\.[^.]+)$`);
if (regex.test(key)) {
return key.replace(regex, "$1");
}
}
return key;
}
/**
* Extract file type from S3 key
* @param {string} key - S3 key like "messages/uuid.jpg"
@@ -50,14 +72,16 @@ class S3OwnershipService {
/**
* Verify message image access - user must be sender OR receiver
* @param {string} key - S3 key
* @param {string} key - S3 key (may be variant like uuid_th.jpg)
* @param {string} userId - User ID making the request
* @returns {Promise<{authorized: boolean, reason?: string}>}
*/
static async verifyMessageAccess(key, userId) {
// Use base key for lookup (DB stores original key, not variants)
const baseKey = this.getBaseKey(key);
const message = await Message.findOne({
where: {
imageFilename: key,
imageFilename: baseKey,
[Op.or]: [{ senderId: userId }, { receiverId: userId }],
},
});
@@ -69,14 +93,16 @@ class S3OwnershipService {
/**
* Verify condition check image access - user must be rental owner OR renter
* @param {string} key - S3 key
* @param {string} key - S3 key (may be variant like uuid_th.jpg)
* @param {string} userId - User ID making the request
* @returns {Promise<{authorized: boolean, reason?: string}>}
*/
static async verifyConditionCheckAccess(key, userId) {
// Use base key for lookup (DB stores original key, not variants)
const baseKey = this.getBaseKey(key);
const check = await ConditionCheck.findOne({
where: {
imageFilenames: { [Op.contains]: [key] },
imageFilenames: { [Op.contains]: [baseKey] },
},
include: [
{