image optimization. Image resizing client side, index added to db, pagination
This commit is contained in:
20
backend/migrations/20251230000001-add-geospatial-index.js
Normal file
20
backend/migrations/20251230000001-add-geospatial-index.js
Normal 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');
|
||||
}
|
||||
};
|
||||
@@ -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: [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user