Skip to content

Sync CT and Map of Pi team repos #51

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Apr 17, 2025
Merged
3 changes: 3 additions & 0 deletions backend/.env.development
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ MONGODB_HOST="mapofpi_mongo:27017"
MONGODB_APP_DATABASE_NAME=demoDB
MONGODB_OPTION_PARAMS=""

MONGODB_MIN_POOL_SIZE=1
MONGODB_MAX_POOL_SIZE=5

SENTRY_DSN="ADD YOUR SENTRY DSN"

PORT=8001
Expand Down
2 changes: 2 additions & 0 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ COPY ./tsconfig.json ./tsconfig.json

# Build the app
RUN yarn build
# Copy swagger docs yml files into build folder for serving
RUN cp -r ./src/config/docs ./build/src/config/docs

# Install PM2
RUN yarn global add pm2
Expand Down
7 changes: 5 additions & 2 deletions backend/src/config/dbConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ export const connectDB = async () => {

try {
// Only log the MongoDB URL in non-production environments
if (process.env.NODE_ENV !== 'production') {
if (env.NODE_ENV !== 'production') {
logger.info(`Connecting to MongoDB with URL: ${mongodbUrl}`);
}
await mongoose.connect(mongodbUrl);
await mongoose.connect(mongodbUrl, {
minPoolSize: env.MONGODB_MIN_POOL_SIZE,
maxPoolSize: env.MONGODB_MAX_POOL_SIZE
});
logger.info("Successful connection to MongoDB.");
} catch (error) {
logger.error('Failed connection to MongoDB:', error);
Expand Down
6 changes: 2 additions & 4 deletions backend/src/models/Seller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,11 @@ const sellerSchema = new Schema<ISeller>(
);

// Creating a text index on the 'name' and 'description' fields
sellerSchema.index({ name: "text", description: "text" });
sellerSchema.index({ 'name': 'text', 'description': 'text' });

// Creating a 2dsphere index for the sell_map_center field
sellerSchema.index({ 'sell_map_center.coordinates': '2dsphere' });
sellerSchema.index(
{ 'updatedAt': -1, 'sell_map_center.coordinates': '2dsphere' }
);
sellerSchema.index({ 'sell_map_center': '2dsphere', 'updatedAt': -1 });

// Creating the Seller model from the schema
const Seller = mongoose.model<ISeller>("Seller", sellerSchema);
Expand Down
43 changes: 42 additions & 1 deletion backend/src/models/enums/restrictedArea.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ export enum RestrictedArea {
SYRIA = "Syria",
REPUBLIC_OF_CRIMEA = "Republic of Crimea",
DONETSK_OBLAST = "Donetsk Oblast",
LUHANSK_OBLAST = "Luhansk Oblast"
LUHANSK_OBLAST = "Luhansk Oblast",
RUSSIA = "Russia",
}

export const RestrictedAreaBoundaries = {
Expand Down Expand Up @@ -80,4 +81,44 @@ export const RestrictedAreaBoundaries = {
[37.7, 47.7],
]],
},
[RestrictedArea.RUSSIA]: {
type: "MultiPolygon", // Need multiple values because MongoDB gets confused with really large 2dsphere Polygons
coordinates: [
[[
[27.3, 77.0],
[27.3, 41.1],
[69.1, 41.1],
[69.1, 77.0],
[27.3, 77.0],
]],
[[
[69.1, 77.8],
[69.1, 49.1],
[114.0, 49.1],
[114.0, 77.8],
[69.1, 77.8],
]],
[[
[114.0, 77.2],
[114.0, 42.3],
[180, 42.3],
[180, 77.2],
[114.0, 77.2],
]],
[[
[-180.0, 62.0],
[-170.0, 62.0],
[-170.0, 72.0],
[-180.0, 72.0],
[-180.0, 62.0],
]],
[[
[44.8, 81.9],
[44.8, 77.9],
[107.9, 77.9],
[107.9, 81.9],
[44.8, 81.9],
]]
],
},
};
4 changes: 2 additions & 2 deletions backend/src/models/misc/SanctionedRegion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ const sanctionedRegionSchema = new Schema<ISanctionedRegion>(
required: true,
},
boundary: {
type: { type: String, enum: ["Polygon"], required: true },
coordinates: { type: [[[Number]]], required: true },
type: { type: String, enum: ["Polygon", "MultiPolygon"], required: true },
coordinates: { type: Array, required: true },
}
}
);
Expand Down
3 changes: 0 additions & 3 deletions backend/src/utils/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ app.use(cookieParser());

// serve static files for Swagger documentation
app.use('/api/docs', express.static(path.join(__dirname, '../config/docs')));
app.use('/api/docs/enum', express.static(path.join(__dirname, '../config/docs/enum')));
// Serve Swagger UI static files
app.use('/api/docs/swagger-ui', express.static(path.join(__dirname, '../node_modules/swagger-ui-dist')));

// Swagger OpenAPI documentation
app.use("/api/docs", docRouter);
Expand Down
2 changes: 2 additions & 0 deletions backend/src/utils/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export const env = {
MONGODB_HOST: process.env.MONGODB_HOST || '',
MONGODB_APP_DATABASE_NAME: process.env.MONGODB_APP_DATABASE_NAME || '',
MONGODB_OPTION_PARAMS: process.env.MONGODB_OPTION_PARAMS || '',
MONGODB_MIN_POOL_SIZE: Number(process.env.MONGODB_MIN_POOL_SIZE) || 1,
MONGODB_MAX_POOL_SIZE: Number(process.env.MONGODB_MAX_POOL_SIZE) || 5,
SENTRY_DSN: process.env.SENTRY_DSN || '',
DEVELOPMENT_URL: process.env.DEVELOPMENT_URL || '',
PRODUCTION_URL: process.env.PRODUCTION_URL || '',
Expand Down
8 changes: 6 additions & 2 deletions backend/src/utils/multer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import multerS3 from "multer-s3";
import { S3 } from "@aws-sdk/client-s3";

import path from "path";
import crypto from "crypto";

import { env } from "./env";

Expand All @@ -17,13 +18,16 @@ const s3 = new S3({
}
});

const getExtension = (fileName: string) => path.extname(fileName).toLowerCase();

const storage = multerS3({
s3,
bucket: env.DIGITAL_OCEAN_BUCKET_NAME,
acl: 'public-read',
contentType: multerS3.AUTO_CONTENT_TYPE,
key: function (request: any, file: any, callback: any) {
callback(null, file.originalname);
const extension = getExtension(file.originalname);
callback(null, `${crypto.randomUUID()}${extension}`);
}
});

Expand All @@ -32,7 +36,7 @@ const fileFilter = (
file: Express.Multer.File,
cb: multer.FileFilterCallback
): void => {
const extension = path.extname(file.originalname).toLowerCase();
const extension = getExtension(file.originalname);
if (!(extension === ".jpg" || extension === ".jpeg" || extension === ".png")) {
const error: any = {
code: "INVALID_FILE_TYPE",
Expand Down
87 changes: 87 additions & 0 deletions backend/test/mockData.json
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,50 @@
"type": "Point",
"coordinates": [39.9930, 49.5582]
}
},
{
"seller_id": "0m0m0m-0m0m-0m0m",
"name": "Test Seller Sanctioned 13",
"description": "Test Seller Sanctioned 13 Description",
"address": "Sanctioned Region Russia West",
"seller_type": "testSeller",
"sell_map_center": {
"type": "Point",
"coordinates": [38.3174, 56.0084]
}
},
{
"seller_id": "0n0n0n-0n0n-0n0n",
"name": "Test Seller Sanctioned 14",
"description": "Test Seller Sanctioned 14 Description",
"address": "Sanctioned Region Russia Central",
"seller_type": "testSeller",
"sell_map_center": {
"type": "Point",
"coordinates": [87.9806, 61.6986]
}
},
{
"seller_id": "0o0o0o-0o0o-0o0o",
"name": "Test Seller Sanctioned 15",
"description": "Test Seller Sanctioned 15 Description",
"address": "Sanctioned Region Russia East",
"seller_type": "testSeller",
"sell_map_center": {
"type": "Point",
"coordinates": [-175.5260, 66.1756]
}
},
{
"seller_id": "0p0p0p-0p0p-0p0p",
"name": "Test Seller Sanctioned 16",
"description": "Test Seller Sanctioned 16 Description",
"address": "Sanctioned Region Russia Polar",
"seller_type": "testSeller",
"sell_map_center": {
"type": "Point",
"coordinates": [60.753873, 80.534107]
}
}
],
"sellerItems": [
Expand Down Expand Up @@ -480,6 +524,49 @@
[37.5, 47.0]
]]
}
},
{
"location": "Russia",
"boundary": {
"type": "MultiPolygon",
"coordinates": [
[[
[27.3, 77.0],
[27.3, 41.1],
[69.1, 41.1],
[69.1, 77.0],
[27.3, 77.0]
]],
[[
[69.1, 77.8],
[69.1, 49.1],
[114.0, 49.1],
[114.0, 77.8],
[69.1, 77.8]
]],
[[
[114.0, 77.2],
[114.0, 42.3],
[180, 42.3],
[180, 77.2],
[114.0, 77.2]
]],
[[
[-180.0, 62.0],
[-170.0, 62.0],
[-170.0, 72.0],
[-180.0, 72.0],
[-180.0, 62.0]
]],
[[
[44.8, 81.9],
[44.8, 77.9],
[107.9, 77.9],
[107.9, 81.9],
[44.8, 81.9]
]]
]
}
}
],
"toggle": [
Expand Down
5 changes: 3 additions & 2 deletions backend/test/services/report.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ jest.mock('../../src/helpers/location', () => ({

describe('reportSanctionedSellers function', () => {
it('should build sanctioned sellers report for affected sellers', async () => {
( reverseLocationDetails as jest.Mock)
(reverseLocationDetails as jest.Mock)
.mockResolvedValueOnce({ data: { display_name: 'Cuba' } })
.mockResolvedValueOnce({ data: { display_name: 'Iran' } })
.mockResolvedValueOnce({ data: { display_name: 'North Korea' } })
.mockResolvedValueOnce({ data: { display_name: 'Syria' } })
.mockResolvedValueOnce({ data: { display_name: 'Republic of Crimea' } })
.mockResolvedValueOnce({ data: { display_name: 'Donetsk Oblast' } })
.mockResolvedValueOnce({ data: { display_name: 'Luhansk Oblast' } });
.mockResolvedValueOnce({ data: { display_name: 'Luhansk Oblast' } })
.mockResolvedValue({ data: { display_name: 'Russia' } });

const sanctionedSellers = await reportSanctionedSellers();

Expand Down
1 change: 1 addition & 0 deletions frontend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ RUN npm ci

# Copy the resources needed to build the app
COPY ./src /app/src
COPY ./i18n /app/i18n
COPY ./messages /app/messages
COPY ./public /app/public
COPY ./tsconfig.json /app/tsconfig.json
Expand Down