Changed controllers to classes, added image functionality
This commit is contained in:
@@ -1,186 +1,188 @@
|
||||
import BaseService from './BaseService.js';
|
||||
import { Op, col } from 'sequelize';
|
||||
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 }) {
|
||||
try {
|
||||
const whereClause = {
|
||||
active: true,
|
||||
searchable: true
|
||||
};
|
||||
if (username) {
|
||||
whereClause.username = { [Op.iLike]: `%${username}%` };
|
||||
}
|
||||
const users = await User.findAll({
|
||||
where: whereClause,
|
||||
include: [
|
||||
{
|
||||
model: UserParam,
|
||||
as: 'user_params',
|
||||
include: [
|
||||
{
|
||||
model: UserParamType,
|
||||
as: 'paramType',
|
||||
where: {
|
||||
description: {
|
||||
[Op.in]: ['gender', 'birthdate']
|
||||
}
|
||||
},
|
||||
required: true
|
||||
}
|
||||
],
|
||||
required: true
|
||||
}
|
||||
]
|
||||
});
|
||||
const results = [];
|
||||
for (const user of users) {
|
||||
const id = user.hashedId;
|
||||
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 decryptedGenderValue = genderParam ? genderParam.value : null;
|
||||
let gender = null;
|
||||
if (decryptedGenderValue) {
|
||||
const genderValue = await UserParamValue.findOne({
|
||||
where: {
|
||||
id: decryptedGenderValue
|
||||
}
|
||||
});
|
||||
gender = genderValue ? genderValue.value : null;
|
||||
}
|
||||
const isWithinAgeRange = (!ageFrom || age >= ageFrom) && (!ageTo || age <= ageTo);
|
||||
if (isWithinAgeRange && (!genders || !genders.length || (gender && genders.includes(gender))) && age >= 14) {
|
||||
results.push({
|
||||
id: id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
gender: gender,
|
||||
age: age
|
||||
});
|
||||
}
|
||||
}
|
||||
return results;
|
||||
} catch (error) {
|
||||
console.error('Error in searchUsers:', error);
|
||||
throw new Error('Error searching users');
|
||||
}
|
||||
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) {
|
||||
try {
|
||||
const requestingUser = await this.getUserByHashedId(requestingUserId);
|
||||
const requestingUserParams = await this.getUserParams(requestingUser.id, ['birthdate']);
|
||||
let requestingUserAge = 0;
|
||||
await this.checkUserAccess(requestingUserId);
|
||||
const user = await this.fetchUserProfile(hashedUserId);
|
||||
if (!user) return null;
|
||||
return this.constructUserProfile(user, requestingUserId);
|
||||
}
|
||||
|
||||
for (const param of requestingUserParams) {
|
||||
if (param.paramType.description === 'birthdate') {
|
||||
requestingUserAge = this.calculateAge(param.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
const user = 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']]
|
||||
}
|
||||
]
|
||||
});
|
||||
if (user) {
|
||||
const userParams = {};
|
||||
await Promise.all(user.user_params.map(async (param) => {
|
||||
const visibilityData = param.param_visibilities?.[0]?.visibility_type;
|
||||
const visibility = visibilityData ? visibilityData.description : 'Invisible';
|
||||
let paramValue = param.value;
|
||||
let paramValueChanged = false;
|
||||
try {
|
||||
const parsedValue = JSON.parse(paramValue);
|
||||
if (Array.isArray(parsedValue)) {
|
||||
paramValue = await Promise.all(parsedValue.map(async (value) => {
|
||||
if (/^\d+$/.test(value)) {
|
||||
const userParamValue = await UserParamValue.findOne({
|
||||
where: {
|
||||
id: parseInt(value, 10),
|
||||
userParamTypeId: param.paramTypeId
|
||||
}
|
||||
});
|
||||
paramValueChanged = true;
|
||||
return userParamValue ? userParamValue.value : value;
|
||||
}
|
||||
return value;
|
||||
}));
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
if (!paramValueChanged) {
|
||||
if (/^\d+$/.test(paramValue)) {
|
||||
const userParamValue = await UserParamValue.findOne({
|
||||
where: {
|
||||
id: parseInt(paramValue, 10),
|
||||
userParamTypeId: param.paramTypeId
|
||||
}
|
||||
});
|
||||
if (userParamValue) {
|
||||
paramValue = userParamValue.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
const paramTypeDescription = param.paramType.description;
|
||||
if (visibility === 'Invisible') {
|
||||
return;
|
||||
}
|
||||
if (visibility === 'All' || (visibility === 'FriendsAndAdults' && requestingUserAge >= 18) || (visibility === 'AdultsOnly' && requestingUserAge >= 18)) {
|
||||
userParams[paramTypeDescription] = {
|
||||
type: param.paramType.datatype,
|
||||
value: paramValue
|
||||
};
|
||||
if (paramTypeDescription === 'birthdate') {
|
||||
userParams['age'] = { value: this.calculateAge(Date.parse(paramValue)), type: "int"};
|
||||
}
|
||||
}
|
||||
}));
|
||||
const userProfile = {
|
||||
username: user.username,
|
||||
registrationDate: user.registrationDate,
|
||||
params: userParams
|
||||
};
|
||||
async createFolder(data) {
|
||||
this.validateFolderData(data);
|
||||
await this.checkUserAccess(data.userId);
|
||||
return await Folder.create(data);
|
||||
}
|
||||
|
||||
return userProfile;
|
||||
}
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error('Error in getProfile:', error);
|
||||
throw new Error('Error getting profile');
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user