Skip to content

Commit

Permalink
Merge pull request #1305 from openworld-community/release/2024-08-18
Browse files Browse the repository at this point in the history
Release/2024 08 18
  • Loading branch information
il12 authored Aug 19, 2024
2 parents f85af1e + 695f9da commit 627388f
Show file tree
Hide file tree
Showing 64 changed files with 1,392 additions and 700 deletions.
8 changes: 8 additions & 0 deletions backend/src/controllers/cities-for-parser.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ class Controller {
if (!city) return null;
return { type: 'city', name: city.name };
}

async findCountryByCityName(cityName: string) {
const city = await CitiesForParserModel.findOne({
alternateNames: cityName
});
if (!city) return null;
return city.countryCode;
}
}

export const citiesForParserController = new Controller();
193 changes: 151 additions & 42 deletions backend/src/controllers/countries-and-cities.controller.ts
Original file line number Diff line number Diff line change
@@ -1,86 +1,195 @@
import fs from 'fs';
import { EventModel } from '../models/event.model';
import { CitiesModel, ICity } from '../models/cities.model';
import { CommonErrorsEnum, SupportedCountries, SupportedLanguages } from '../../../common/const';
import { CountriesForParserModel } from '../models/countries-for-parser.model';
import { citiesForParserController } from './cities-for-parser.controller';
import { countriesForParserController } from './countries-for-parser.controller';

class CountriesAndCitiesController {
countries: string[];
async getLocalizedCities(lang: SupportedLanguages) {
const pipeline = [
{
$unset: ['countryCode', 'alternateNames', '_id']
}
];
const cities = await CitiesModel.aggregate(pipeline).exec();
return cities.map((city) => city[lang]);
}

citiesByCountry: { [key: string]: string[] } = {};
async getLocalizedCountries(lang: SupportedLanguages) {
const pipeline = [
{
$match: {
iso_3166_1_alpha_2_codes: {
$in: Object.values(SupportedCountries)
}
}
}
];
const countries = await CountriesForParserModel.aggregate(pipeline).exec();
return countries.map((country) => {
if (lang === SupportedLanguages.RUSSIAN) return country.russian_short!;
return country.english_short!;
});
}

constructor() {
const map = JSON.parse(fs.readFileSync('./assets/countries.json', 'utf8'));
async getLocalizedCityName(cityName: string, lang: SupportedLanguages) {
if (cityName === '') return '';
const city = await CitiesModel.findOne({
$or: [{ en: cityName }, { ru: cityName }, { alternateNames: cityName }]
});
if (!city) return cityName;
return city[lang];
}

this.countries = Object.keys(map);
this.citiesByCountry = map;
async getLocalizedCountryName(countryName: string, lang: SupportedLanguages) {
if (countryName === '') return '';
const country = await CountriesForParserModel.findOne({
$or: [
{ english_short: countryName },
{ french_short: countryName },
{ spanish_short: countryName },
{ russian_short: countryName }
]
});
if (!country) throw new Error(CommonErrorsEnum.COUNTRY_NOT_FOUND);
if (lang === SupportedLanguages.RUSSIAN) return country.russian_short!;
return country.english_short!;
}

async getCountryCodeByName(countryName: string) {
if (countryName === '') return '';
const country = await CountriesForParserModel.findOne({
$or: [
{ english_short: countryName },
{ french_short: countryName },
{ spanish_short: countryName },
{ russian_short: countryName }
]
});
if (!country) throw new Error(CommonErrorsEnum.COUNTRY_NOT_FOUND);
return country.iso_3166_1_alpha_2_codes!;
}

getCountryByCity(city: string) {
const { countries } = this;
if (countries.includes(city)) return city;
const possibleCountries = countries.filter((country) =>
this.citiesByCountry[country].includes(city)
async getCountryByCity(city: string) {
const countryCode = await citiesForParserController.findCountryByCityName(city);
if (!countryCode) throw new Error(CommonErrorsEnum.CITY_NOT_FOUND);
const countryName = await countriesForParserController.findEnglishCountryNameByCountryCode(
countryCode
);
return possibleCountries[0];
if (!countryName) throw new Error(CommonErrorsEnum.COUNTRY_NOT_FOUND);
return countryName;
}

getCitiesByCountry(country: string) {
const citiesByCountry = this.citiesByCountry[country];
return citiesByCountry;
async getCitiesByCountry(country: SupportedCountries, lang: SupportedLanguages) {
const pipeline = [
{
$match: {
countryCode: country
}
}
];

const cities = await CitiesModel.aggregate(pipeline).exec();
return cities.map((city) => city[lang]);
}

async getUsedCountries() {
async getUsedCountries(lang: SupportedLanguages) {
const countries: string[] = await EventModel.distinct('location.country', {
'meta.moderation.status': { $nin: ['declined', 'in-progress'] },
$expr: {
$gte: [{ $add: ['$date', { $multiply: [1000, '$durationInSeconds'] }] }, Date.now()]
},
'location.country': { $nin: [''] }
});
return countries;
return Promise.all(
countries.map(async (country) => this.getLocalizedCountryName(country, lang))
);
}

async getUsedCitiesByCountry(country: string) {
const cities: string[] = await EventModel.distinct('location.city', {
const unprocessedCities: string[] = await EventModel.distinct('location.city', {
'location.country': country,
'meta.moderation.status': { $nin: ['declined', 'in-progress'] },
'location.city': { $nin: [''] },
$expr: {
$gte: [{ $add: ['$date', { $multiply: [1000, '$durationInSeconds'] }] }, Date.now()]
}
});
return cities;

const pipeline = [
{
$match: {
$or: [
{ en: { $in: unprocessedCities } },
{ ru: { $in: unprocessedCities } },
{ alternateNames: { $in: unprocessedCities } }
]
}
},
{
$unset: ['countryCode', 'alternateNames', '_id']
}
];

return CitiesModel.aggregate(pipeline).exec();
}

async getUsedCities() {
const cities: string[] = await EventModel.distinct('location.city', {
const unprocessedCities: string[] = await EventModel.distinct('location.city', {
'location.country': { $in: ['Serbia', 'Montenegro'] },
'meta.moderation.status': { $nin: ['declined', 'in-progress'] },
'location.city': { $nin: [''] },
$expr: {
$gte: [{ $add: ['$date', { $multiply: [1000, '$durationInSeconds'] }] }, Date.now()]
}
});
return cities;
}

getRandomPair({ country, city }: { country?: string; city?: string }) {
const getRandomCountry = () => {
const randomCountryIndex = Math.floor(Math.random() * this.countries.length);
const randomCountry = this.countries[randomCountryIndex];
return randomCountry;
};

const getRandomCity = (randomCountry: string) => {
const randomCityIndex = Math.floor(
Math.random() * (this.citiesByCountry[randomCountry]?.length || 0)
);
const randomCity = this.citiesByCountry[randomCountry]?.[randomCityIndex];
return randomCity;
};

const newCountry = country || getRandomCountry();
const newCity = city || getRandomCity(newCountry);

return { country: newCountry, city: newCity };
const pipeline = [
{
$match: {
$or: [
{ en: { $in: unprocessedCities } },
{ ru: { $in: unprocessedCities } },
{ alternateNames: { $in: unprocessedCities } }
]
}
},
{
$unset: ['alternateNames', '_id']
}
];

const citiesWithLocalization = await CitiesModel.aggregate(pipeline).exec();
const usedCities = citiesWithLocalization.reduce(
(accum, city: ICity) => {
const formattedCity = {
en: city.en,
ru: city.ru
};
if (city.countryCode === SupportedCountries.SERBIA) {
accum[0].cities.push(formattedCity);
}
if (city.countryCode === SupportedCountries.MONTENEGRO) {
accum[1].cities.push(formattedCity);
}
return accum;
},
[
{
en: 'Serbia',
ru: 'Сербия',
cities: []
},
{
en: 'Montengro',
ru: 'Черногория',
cities: []
}
]
);

return usedCities;
}
}

Expand Down
8 changes: 8 additions & 0 deletions backend/src/controllers/countries-for-parser.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ class Controller {
if (!country) return null;
return { type: 'country', name: country.english_short };
}

async findEnglishCountryNameByCountryCode(countryCode: string) {
const country = await CountriesForParserModel.findOne({
iso_3166_1_alpha_2_codes: { $regex: countryCode, $options: 'i' }
});
if (!country) return null;
return country.english_short;
}
}

export const countriesForParserController = new Controller();
Loading

0 comments on commit 627388f

Please sign in to comment.