190 lines
7.1 KiB
JavaScript
190 lines
7.1 KiB
JavaScript
import BaseService from './BaseService.js';
|
|
import { Op } from 'sequelize';
|
|
import User from '../models/community/user.js';
|
|
import UserParam from '../models/community/user_param.js';
|
|
import UserParamType from '../models/type/user_param.js';
|
|
import UserParamValue from '../models/type/user_param_value.js';
|
|
import UserParamVisibility from '../models/community/user_param_visibility.js';
|
|
import UserParamVisibilityType from '../models/type/user_param_visibility.js';
|
|
import Folder from '../models/community/folder.js';
|
|
import Image from '../models/community/image.js';
|
|
|
|
class SocialNetworkService extends BaseService {
|
|
async searchUsers({ username, ageFrom, ageTo, genders }) {
|
|
const whereClause = this.buildSearchWhereClause(username);
|
|
const users = await User.findAll({ where: whereClause, include: this.getUserParamsInclude() });
|
|
return this.filterUsersByCriteria(users, ageFrom, ageTo, genders);
|
|
}
|
|
|
|
async getProfile(hashedUserId, requestingUserId) {
|
|
await this.checkUserAccess(requestingUserId);
|
|
const user = await this.fetchUserProfile(hashedUserId);
|
|
if (!user) return null;
|
|
return this.constructUserProfile(user, requestingUserId);
|
|
}
|
|
|
|
async createFolder(data) {
|
|
this.validateFolderData(data);
|
|
await this.checkUserAccess(data.userId);
|
|
return await Folder.create(data);
|
|
}
|
|
|
|
async getFolders(userId) {
|
|
await this.checkUserAccess(userId);
|
|
return await Folder.findAll({ where: { userId } });
|
|
}
|
|
|
|
async uploadImage(imageData) {
|
|
this.validateImageData(imageData);
|
|
await this.checkUserAccess(imageData.userId);
|
|
return await Image.create(imageData);
|
|
}
|
|
|
|
async getImage(imageId) {
|
|
const image = await Image.findByPk(imageId);
|
|
if (!image) throw new Error('Image not found');
|
|
await this.checkUserAccess(image.userId);
|
|
return image;
|
|
}
|
|
|
|
async checkUserAccess(userId) {
|
|
const user = await User.findByPk(userId);
|
|
if (!user || !user.active) throw new Error('Access denied: User not found or inactive');
|
|
}
|
|
|
|
validateFolderData(data) {
|
|
if (!data.name || typeof data.name !== 'string') throw new Error('Invalid folder data: Name is required');
|
|
}
|
|
|
|
validateImageData(imageData) {
|
|
if (!imageData.url || typeof imageData.url !== 'string') throw new Error('Invalid image data: URL is required');
|
|
}
|
|
|
|
buildSearchWhereClause(username) {
|
|
const whereClause = { active: true, searchable: true };
|
|
if (username) {
|
|
whereClause.username = { [Op.iLike]: `%${username}%` };
|
|
}
|
|
return whereClause;
|
|
}
|
|
|
|
getUserParamsInclude() {
|
|
return [
|
|
{
|
|
model: UserParam,
|
|
as: 'user_params',
|
|
include: [{ model: UserParamType, as: 'paramType', required: true }]
|
|
}
|
|
];
|
|
}
|
|
|
|
filterUsersByCriteria(users, ageFrom, ageTo, genders) {
|
|
const results = [];
|
|
for (const user of users) {
|
|
const userDetails = this.extractUserDetails(user);
|
|
if (this.isUserValid(userDetails, ageFrom, ageTo, genders)) {
|
|
results.push(userDetails);
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
extractUserDetails(user) {
|
|
const birthdateParam = user.user_params.find(param => param.paramType.description === 'birthdate');
|
|
const genderParam = user.user_params.find(param => param.paramType.description === 'gender');
|
|
const age = birthdateParam ? this.calculateAge(birthdateParam.value) : null;
|
|
const gender = genderParam ? this.getGenderValue(genderParam.value) : null;
|
|
return {
|
|
id: user.hashedId,
|
|
username: user.username,
|
|
email: user.email,
|
|
gender,
|
|
age
|
|
};
|
|
}
|
|
|
|
async getGenderValue(genderId) {
|
|
const genderValue = await UserParamValue.findOne({ where: { id: genderId } });
|
|
return genderValue ? genderValue.value : null;
|
|
}
|
|
|
|
isUserValid(userDetails, ageFrom, ageTo, genders) {
|
|
const { age, gender } = userDetails;
|
|
const isWithinAgeRange = (!ageFrom || age >= ageFrom) && (!ageTo || age <= ageTo);
|
|
const isGenderValid = !genders || !genders.length || (gender && genders.includes(gender));
|
|
return isWithinAgeRange && isGenderValid && age >= 14;
|
|
}
|
|
|
|
async fetchUserProfile(hashedUserId) {
|
|
return await User.findOne({
|
|
where: { hashedId: hashedUserId, active: true, searchable: true },
|
|
include: [
|
|
{
|
|
model: UserParam,
|
|
as: 'user_params',
|
|
include: [
|
|
{ model: UserParamType, as: 'paramType' },
|
|
{ model: UserParamVisibility, as: 'param_visibilities', include: [{ model: UserParamVisibilityType, as: 'visibility_type' }] }
|
|
],
|
|
order: [['order_id', 'asc']]
|
|
}
|
|
]
|
|
});
|
|
}
|
|
|
|
async constructUserProfile(user, requestingUserId) {
|
|
const userParams = {};
|
|
const requestingUserAge = await this.getUserAge(requestingUserId);
|
|
for (const param of user.user_params) {
|
|
const visibility = param.param_visibilities?.[0]?.visibility_type?.description || 'Invisible';
|
|
if (visibility === 'Invisible') continue;
|
|
if (this.isVisibleToUser(visibility, requestingUserAge)) {
|
|
userParams[param.paramType.description] = {
|
|
type: param.paramType.datatype,
|
|
value: await this.getParamValue(param)
|
|
};
|
|
}
|
|
}
|
|
return {
|
|
username: user.username,
|
|
registrationDate: user.registrationDate,
|
|
params: userParams
|
|
};
|
|
}
|
|
|
|
async getUserAge(userId) {
|
|
const params = await this.getUserParams(userId, ['birthdate']);
|
|
const birthdateParam = params.find(param => param.paramType.description === 'birthdate');
|
|
return birthdateParam ? this.calculateAge(birthdateParam.value) : 0;
|
|
}
|
|
|
|
isVisibleToUser(visibility, requestingUserAge) {
|
|
return visibility === 'All' ||
|
|
(visibility === 'FriendsAndAdults' && requestingUserAge >= 18) ||
|
|
(visibility === 'AdultsOnly' && requestingUserAge >= 18);
|
|
}
|
|
|
|
async getParamValue(param) {
|
|
let paramValue = param.value;
|
|
try {
|
|
const parsedValue = JSON.parse(paramValue);
|
|
if (Array.isArray(parsedValue)) {
|
|
paramValue = await Promise.all(parsedValue.map(value => this.getValueFromDatabase(value, param.paramTypeId)));
|
|
} else if (/^\d+$/.test(paramValue)) {
|
|
paramValue = await this.getValueFromDatabase(paramValue, param.paramTypeId);
|
|
}
|
|
} catch (e) {
|
|
}
|
|
return paramValue;
|
|
}
|
|
|
|
async getValueFromDatabase(value, paramTypeId) {
|
|
const userParamValue = await UserParamValue.findOne({
|
|
where: { id: parseInt(value, 10), userParamTypeId: paramTypeId }
|
|
});
|
|
return userParamValue ? userParamValue.value : value;
|
|
}
|
|
}
|
|
|
|
export default SocialNetworkService;
|