Add adult verification and erotic moderation features: Implement new routes and controller methods for managing adult verification requests, status updates, and document retrieval. Introduce erotic moderation actions and reports, enhancing administrative capabilities. Update chat and navigation controllers to support adult content filtering and access control. Enhance user parameter handling for adult verification status and requests, improving overall user experience and compliance.
This commit is contained in:
@@ -8,6 +8,8 @@ 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';
|
||||
import EroticVideo from '../models/community/erotic_video.js';
|
||||
import EroticContentReport from '../models/community/erotic_content_report.js';
|
||||
import ImageVisibilityType from '../models/type/image_visibility.js';
|
||||
import FolderImageVisibility from '../models/community/folder_image_visibility.js';
|
||||
import ImageImageVisibility from '../models/community/image_image_visibility.js';
|
||||
@@ -30,6 +32,150 @@ const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
class SocialNetworkService extends BaseService {
|
||||
normalizeAdultVerificationStatus(value) {
|
||||
if (!value) return 'none';
|
||||
const normalized = String(value).trim().toLowerCase();
|
||||
return ['pending', 'approved', 'rejected'].includes(normalized) ? normalized : 'none';
|
||||
}
|
||||
|
||||
async getAdultAccessState(userId) {
|
||||
const params = await this.getUserParams(userId, ['birthdate', 'adult_verification_status', 'adult_upload_blocked']);
|
||||
const birthdateParam = params.find(param => param.paramType.description === 'birthdate');
|
||||
const statusParam = params.find(param => param.paramType.description === 'adult_verification_status');
|
||||
const uploadBlockedParam = params.find(param => param.paramType.description === 'adult_upload_blocked');
|
||||
const age = birthdateParam ? this.calculateAge(birthdateParam.value) : 0;
|
||||
const adultVerificationStatus = this.normalizeAdultVerificationStatus(statusParam?.value);
|
||||
return {
|
||||
age,
|
||||
isAdult: age >= 18,
|
||||
adultVerificationStatus,
|
||||
adultAccessEnabled: age >= 18 && adultVerificationStatus === 'approved',
|
||||
adultUploadBlocked: String(uploadBlockedParam?.value).toLowerCase() === 'true'
|
||||
};
|
||||
}
|
||||
|
||||
async requireAdultAreaAccessByHash(hashedId) {
|
||||
const userId = await this.checkUserAccess(hashedId);
|
||||
const adultAccess = await this.getAdultAccessState(userId);
|
||||
if (!adultAccess.adultAccessEnabled) {
|
||||
const error = new Error('Adult area access denied');
|
||||
error.status = 403;
|
||||
throw error;
|
||||
}
|
||||
return userId;
|
||||
}
|
||||
|
||||
async ensureAdultUploadsAllowed(userId) {
|
||||
const adultAccess = await this.getAdultAccessState(userId);
|
||||
if (adultAccess.adultUploadBlocked) {
|
||||
const error = new Error('Adult uploads are blocked');
|
||||
error.status = 403;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async resolveEroticTarget(targetType, targetId) {
|
||||
if (targetType === 'image') {
|
||||
const image = await Image.findOne({
|
||||
where: {
|
||||
id: targetId,
|
||||
isAdultContent: true
|
||||
}
|
||||
});
|
||||
if (!image) {
|
||||
throw new Error('Target not found');
|
||||
}
|
||||
return { targetType, target: image, ownerId: image.userId };
|
||||
}
|
||||
if (targetType === 'video') {
|
||||
const video = await EroticVideo.findByPk(targetId);
|
||||
if (!video) {
|
||||
throw new Error('Target not found');
|
||||
}
|
||||
return { targetType, target: video, ownerId: video.userId };
|
||||
}
|
||||
throw new Error('Unsupported target type');
|
||||
}
|
||||
|
||||
async ensureRootFolder(userId) {
|
||||
let rootFolder = await Folder.findOne({
|
||||
where: { parentId: null, userId, isAdultArea: false },
|
||||
include: [{
|
||||
model: ImageVisibilityType,
|
||||
through: { model: FolderImageVisibility },
|
||||
attributes: ['id'],
|
||||
}]
|
||||
});
|
||||
if (rootFolder) {
|
||||
return rootFolder;
|
||||
}
|
||||
|
||||
const user = await User.findOne({ where: { id: userId } });
|
||||
const visibility = await ImageVisibilityType.findOne({ where: { description: 'everyone' } });
|
||||
rootFolder = await Folder.create({
|
||||
name: user.username,
|
||||
parentId: null,
|
||||
userId,
|
||||
isAdultArea: false
|
||||
});
|
||||
if (visibility) {
|
||||
await FolderImageVisibility.create({
|
||||
folderId: rootFolder.id,
|
||||
visibilityTypeId: visibility.id
|
||||
});
|
||||
}
|
||||
return await Folder.findOne({
|
||||
where: { id: rootFolder.id },
|
||||
include: [{
|
||||
model: ImageVisibilityType,
|
||||
through: { model: FolderImageVisibility },
|
||||
attributes: ['id'],
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
async ensureAdultRootFolder(userId) {
|
||||
const rootFolder = await this.ensureRootFolder(userId);
|
||||
let adultRoot = await Folder.findOne({
|
||||
where: {
|
||||
parentId: rootFolder.id,
|
||||
userId,
|
||||
isAdultArea: true,
|
||||
name: 'Erotik'
|
||||
},
|
||||
include: [{
|
||||
model: ImageVisibilityType,
|
||||
through: { model: FolderImageVisibility },
|
||||
attributes: ['id'],
|
||||
}]
|
||||
});
|
||||
if (adultRoot) {
|
||||
return adultRoot;
|
||||
}
|
||||
|
||||
const adultsVisibility = await ImageVisibilityType.findOne({ where: { description: 'adults' } });
|
||||
adultRoot = await Folder.create({
|
||||
name: 'Erotik',
|
||||
parentId: rootFolder.id,
|
||||
userId,
|
||||
isAdultArea: true
|
||||
});
|
||||
if (adultsVisibility) {
|
||||
await FolderImageVisibility.create({
|
||||
folderId: adultRoot.id,
|
||||
visibilityTypeId: adultsVisibility.id
|
||||
});
|
||||
}
|
||||
return await Folder.findOne({
|
||||
where: { id: adultRoot.id },
|
||||
include: [{
|
||||
model: ImageVisibilityType,
|
||||
through: { model: FolderImageVisibility },
|
||||
attributes: ['id'],
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
async searchUsers({ hashedUserId, username, ageFrom, ageTo, genders }) {
|
||||
const whereClause = this.buildSearchWhereClause(username);
|
||||
const user = await this.loadUserByHash(hashedUserId);
|
||||
@@ -49,15 +195,19 @@ class SocialNetworkService extends BaseService {
|
||||
return this.constructUserProfile(user, requestingUserId);
|
||||
}
|
||||
|
||||
async createFolder(hashedUserId, data, folderId) {
|
||||
async createFolder(hashedUserId, data, folderId, options = {}) {
|
||||
await this.checkUserAccess(hashedUserId);
|
||||
const user = await this.loadUserByHash(hashedUserId);
|
||||
if (!user) {
|
||||
throw new Error('User not found');
|
||||
}
|
||||
const isAdultArea = Boolean(options.isAdultArea);
|
||||
if (isAdultArea) {
|
||||
await this.requireAdultAreaAccessByHash(hashedUserId);
|
||||
}
|
||||
console.log('given data', data, folderId);
|
||||
const parentFolder = data.parentId ? await Folder.findOne({
|
||||
where: { id: data.parentId, userId: user.id }
|
||||
where: { id: data.parentId, userId: user.id, isAdultArea }
|
||||
}) : null;
|
||||
if (data.parentId && !parentFolder) {
|
||||
throw new Error('Parent folder not found');
|
||||
@@ -68,11 +218,12 @@ class SocialNetworkService extends BaseService {
|
||||
newFolder = await Folder.create({
|
||||
parentId: parentFolder.id || null,
|
||||
userId: user.id,
|
||||
name: data.name
|
||||
name: data.name,
|
||||
isAdultArea
|
||||
});
|
||||
} else {
|
||||
newFolder = await Folder.findOne({
|
||||
where: { id: folderId, userId: user.id }
|
||||
where: { id: folderId, userId: user.id, isAdultArea }
|
||||
});
|
||||
if (!newFolder) {
|
||||
throw new Error('Folder not found or user does not own the folder');
|
||||
@@ -94,38 +245,8 @@ class SocialNetworkService extends BaseService {
|
||||
|
||||
async getFolders(hashedId) {
|
||||
const userId = await this.checkUserAccess(hashedId);
|
||||
let rootFolder = await Folder.findOne({
|
||||
where: { parentId: null, userId },
|
||||
include: [{
|
||||
model: ImageVisibilityType,
|
||||
through: { model: FolderImageVisibility },
|
||||
attributes: ['id'],
|
||||
}]
|
||||
});
|
||||
if (!rootFolder) {
|
||||
const user = await User.findOne({ where: { id: userId } });
|
||||
const visibility = await ImageVisibilityType.findOne({
|
||||
where: { description: 'everyone' }
|
||||
});
|
||||
rootFolder = await Folder.create({
|
||||
name: user.username,
|
||||
parentId: null,
|
||||
userId
|
||||
});
|
||||
await FolderImageVisibility.create({
|
||||
folderId: rootFolder.id,
|
||||
visibilityTypeId: visibility.id
|
||||
});
|
||||
rootFolder = await Folder.findOne({
|
||||
where: { id: rootFolder.id },
|
||||
include: [{
|
||||
model: ImageVisibilityType,
|
||||
through: { model: FolderImageVisibility },
|
||||
attributes: ['id'],
|
||||
}]
|
||||
});
|
||||
}
|
||||
const children = await this.getSubFolders(rootFolder.id, userId);
|
||||
const rootFolder = await this.ensureRootFolder(userId);
|
||||
const children = await this.getSubFolders(rootFolder.id, userId, false);
|
||||
rootFolder = rootFolder.get();
|
||||
rootFolder.visibilityTypeIds = rootFolder.image_visibility_types.map(v => v.id);
|
||||
delete rootFolder.image_visibility_types;
|
||||
@@ -133,9 +254,9 @@ class SocialNetworkService extends BaseService {
|
||||
return rootFolder;
|
||||
}
|
||||
|
||||
async getSubFolders(parentId, userId) {
|
||||
async getSubFolders(parentId, userId, isAdultArea = false) {
|
||||
const folders = await Folder.findAll({
|
||||
where: { parentId, userId },
|
||||
where: { parentId, userId, isAdultArea },
|
||||
include: [{
|
||||
model: ImageVisibilityType,
|
||||
through: { model: FolderImageVisibility },
|
||||
@@ -146,7 +267,7 @@ class SocialNetworkService extends BaseService {
|
||||
]
|
||||
});
|
||||
for (const folder of folders) {
|
||||
const children = await this.getSubFolders(folder.id, userId);
|
||||
const children = await this.getSubFolders(folder.id, userId, isAdultArea);
|
||||
const visibilityTypeIds = folder.image_visibility_types.map(v => v.id);
|
||||
folder.setDataValue('visibilityTypeIds', visibilityTypeIds);
|
||||
folder.setDataValue('children', children);
|
||||
@@ -160,13 +281,15 @@ class SocialNetworkService extends BaseService {
|
||||
const folder = await Folder.findOne({
|
||||
where: {
|
||||
id: folderId,
|
||||
userId
|
||||
userId,
|
||||
isAdultArea: false
|
||||
}
|
||||
});
|
||||
if (!folder) throw new Error('Folder not found');
|
||||
return await Image.findAll({
|
||||
where: {
|
||||
folderId: folder.id
|
||||
folderId: folder.id,
|
||||
isAdultContent: false
|
||||
},
|
||||
order: [
|
||||
['title', 'asc']
|
||||
@@ -176,13 +299,13 @@ class SocialNetworkService extends BaseService {
|
||||
|
||||
async uploadImage(hashedId, file, formData) {
|
||||
const userId = await this.getUserId(hashedId);
|
||||
const processedImageName = await this.processAndUploadUserImage(file);
|
||||
const newImage = await this.createImageRecord(formData, userId, file, processedImageName);
|
||||
const processedImageName = await this.processAndUploadUserImage(file, 'user');
|
||||
const newImage = await this.createImageRecord(formData, userId, file, processedImageName, { isAdultContent: false });
|
||||
await this.saveImageVisibilities(newImage.id, formData.visibility);
|
||||
return newImage;
|
||||
}
|
||||
|
||||
async processAndUploadUserImage(file) {
|
||||
async processAndUploadUserImage(file, storageType = 'user') {
|
||||
try {
|
||||
const img = sharp(file.buffer);
|
||||
const metadata = await img.metadata();
|
||||
@@ -199,7 +322,7 @@ class SocialNetworkService extends BaseService {
|
||||
withoutEnlargement: true
|
||||
});
|
||||
const newFileName = this.generateUniqueFileName(file.originalname);
|
||||
const filePath = this.buildFilePath(newFileName, 'user');
|
||||
const filePath = this.buildFilePath(newFileName, storageType);
|
||||
await resizedImg.toFile(filePath);
|
||||
return newFileName;
|
||||
} catch (error) {
|
||||
@@ -231,7 +354,7 @@ class SocialNetworkService extends BaseService {
|
||||
}
|
||||
}
|
||||
|
||||
async createImageRecord(formData, userId, file, fileName) {
|
||||
async createImageRecord(formData, userId, file, fileName, options = {}) {
|
||||
try {
|
||||
return await Image.create({
|
||||
title: formData.title,
|
||||
@@ -240,6 +363,7 @@ class SocialNetworkService extends BaseService {
|
||||
hash: fileName,
|
||||
folderId: formData.folderId,
|
||||
userId: userId,
|
||||
isAdultContent: Boolean(options.isAdultContent),
|
||||
});
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to create image record: ${error.message}`);
|
||||
@@ -271,6 +395,7 @@ class SocialNetworkService extends BaseService {
|
||||
async getImage(imageId) {
|
||||
const image = await Image.findByPk(imageId);
|
||||
if (!image) throw new Error('Image not found');
|
||||
if (image.isAdultContent) throw new Error('Access denied');
|
||||
await this.checkUserAccess(image.userId);
|
||||
return image;
|
||||
}
|
||||
@@ -455,6 +580,9 @@ class SocialNetworkService extends BaseService {
|
||||
if (!image) {
|
||||
throw new Error('Image not found');
|
||||
}
|
||||
if (image.isAdultContent) {
|
||||
throw new Error('Access denied');
|
||||
}
|
||||
const userId = await this.checkUserAccess(hashedUserId);
|
||||
const hasAccess = await this.checkUserImageAccess(userId, image.id);
|
||||
if (!hasAccess) {
|
||||
@@ -467,6 +595,178 @@ class SocialNetworkService extends BaseService {
|
||||
return imagePath;
|
||||
}
|
||||
|
||||
async getAdultFolders(hashedId) {
|
||||
const userId = await this.requireAdultAreaAccessByHash(hashedId);
|
||||
const rootFolder = await this.ensureAdultRootFolder(userId);
|
||||
const children = await this.getSubFolders(rootFolder.id, userId, true);
|
||||
const data = rootFolder.get();
|
||||
data.visibilityTypeIds = data.image_visibility_types.map(v => v.id);
|
||||
delete data.image_visibility_types;
|
||||
data.children = children;
|
||||
return data;
|
||||
}
|
||||
|
||||
async getAdultFolderImageList(hashedId, folderId) {
|
||||
const userId = await this.requireAdultAreaAccessByHash(hashedId);
|
||||
const folder = await Folder.findOne({
|
||||
where: { id: folderId, userId, isAdultArea: true }
|
||||
});
|
||||
if (!folder) {
|
||||
throw new Error('Folder not found');
|
||||
}
|
||||
return await Image.findAll({
|
||||
where: {
|
||||
folderId: folder.id,
|
||||
isAdultContent: true,
|
||||
userId
|
||||
},
|
||||
order: [['title', 'asc']]
|
||||
});
|
||||
}
|
||||
|
||||
async createAdultFolder(hashedId, data, folderId) {
|
||||
await this.requireAdultAreaAccessByHash(hashedId);
|
||||
if (!data.parentId) {
|
||||
const userId = await this.checkUserAccess(hashedId);
|
||||
const adultRoot = await this.ensureAdultRootFolder(userId);
|
||||
data.parentId = adultRoot.id;
|
||||
}
|
||||
return this.createFolder(hashedId, data, folderId, { isAdultArea: true });
|
||||
}
|
||||
|
||||
async uploadAdultImage(hashedId, file, formData) {
|
||||
const userId = await this.requireAdultAreaAccessByHash(hashedId);
|
||||
await this.ensureAdultUploadsAllowed(userId);
|
||||
const folder = await Folder.findOne({
|
||||
where: {
|
||||
id: formData.folderId,
|
||||
userId,
|
||||
isAdultArea: true
|
||||
}
|
||||
});
|
||||
if (!folder) {
|
||||
throw new Error('Folder not found');
|
||||
}
|
||||
const processedImageName = await this.processAndUploadUserImage(file, 'erotic');
|
||||
const newImage = await this.createImageRecord(formData, userId, file, processedImageName, { isAdultContent: true });
|
||||
await this.saveImageVisibilities(newImage.id, formData.visibility);
|
||||
return newImage;
|
||||
}
|
||||
|
||||
async getAdultImageFilePath(hashedId, hash) {
|
||||
const userId = await this.requireAdultAreaAccessByHash(hashedId);
|
||||
const image = await Image.findOne({
|
||||
where: {
|
||||
hash,
|
||||
userId,
|
||||
isAdultContent: true
|
||||
}
|
||||
});
|
||||
if (!image) {
|
||||
throw new Error('Image not found');
|
||||
}
|
||||
if (image.isModeratedHidden) {
|
||||
throw new Error('Image hidden by moderation');
|
||||
}
|
||||
const imagePath = this.buildFilePath(image.hash, 'erotic');
|
||||
if (!fs.existsSync(imagePath)) {
|
||||
throw new Error(`File "${imagePath}" not found`);
|
||||
}
|
||||
return imagePath;
|
||||
}
|
||||
|
||||
async listEroticVideos(hashedId) {
|
||||
const userId = await this.requireAdultAreaAccessByHash(hashedId);
|
||||
return await EroticVideo.findAll({
|
||||
where: { userId },
|
||||
order: [['createdAt', 'DESC']]
|
||||
});
|
||||
}
|
||||
|
||||
async uploadEroticVideo(hashedId, file, formData) {
|
||||
const userId = await this.requireAdultAreaAccessByHash(hashedId);
|
||||
await this.ensureAdultUploadsAllowed(userId);
|
||||
if (!file) {
|
||||
throw new Error('Video file is required');
|
||||
}
|
||||
const allowedMimeTypes = ['video/mp4', 'video/webm', 'video/ogg', 'video/quicktime'];
|
||||
if (!allowedMimeTypes.includes(file.mimetype)) {
|
||||
throw new Error('Unsupported video format');
|
||||
}
|
||||
|
||||
const fileName = this.generateUniqueFileName(file.originalname);
|
||||
const filePath = this.buildFilePath(fileName, 'erotic-video');
|
||||
await this.saveFile(file.buffer, filePath);
|
||||
|
||||
return await EroticVideo.create({
|
||||
title: formData.title || file.originalname,
|
||||
description: formData.description || null,
|
||||
originalFileName: file.originalname,
|
||||
hash: fileName,
|
||||
mimeType: file.mimetype,
|
||||
userId
|
||||
});
|
||||
}
|
||||
|
||||
async getEroticVideoFilePath(hashedId, hash) {
|
||||
const userId = await this.requireAdultAreaAccessByHash(hashedId);
|
||||
const video = await EroticVideo.findOne({
|
||||
where: { hash, userId }
|
||||
});
|
||||
if (!video) {
|
||||
throw new Error('Video not found');
|
||||
}
|
||||
if (video.isModeratedHidden) {
|
||||
throw new Error('Video hidden by moderation');
|
||||
}
|
||||
const videoPath = this.buildFilePath(video.hash, 'erotic-video');
|
||||
if (!fs.existsSync(videoPath)) {
|
||||
throw new Error(`File "${videoPath}" not found`);
|
||||
}
|
||||
return { filePath: videoPath, mimeType: video.mimeType };
|
||||
}
|
||||
|
||||
async createEroticContentReport(hashedId, payload) {
|
||||
const reporterId = await this.requireAdultAreaAccessByHash(hashedId);
|
||||
const targetType = String(payload.targetType || '').trim().toLowerCase();
|
||||
const targetId = Number(payload.targetId);
|
||||
const reason = String(payload.reason || '').trim().toLowerCase();
|
||||
const note = payload.note ? String(payload.note).trim() : null;
|
||||
|
||||
if (!['image', 'video'].includes(targetType) || !Number.isInteger(targetId) || targetId <= 0) {
|
||||
throw new Error('Invalid report target');
|
||||
}
|
||||
if (!['suspected_minor', 'non_consensual', 'violence', 'harassment', 'spam', 'other'].includes(reason)) {
|
||||
throw new Error('Invalid report reason');
|
||||
}
|
||||
|
||||
const { ownerId } = await this.resolveEroticTarget(targetType, targetId);
|
||||
if (ownerId === reporterId) {
|
||||
throw new Error('Own content cannot be reported');
|
||||
}
|
||||
|
||||
const existingOpen = await EroticContentReport.findOne({
|
||||
where: {
|
||||
reporterId,
|
||||
targetType,
|
||||
targetId,
|
||||
status: 'open'
|
||||
}
|
||||
});
|
||||
if (existingOpen) {
|
||||
return existingOpen;
|
||||
}
|
||||
|
||||
return await EroticContentReport.create({
|
||||
reporterId,
|
||||
targetType,
|
||||
targetId,
|
||||
reason,
|
||||
note,
|
||||
status: 'open'
|
||||
});
|
||||
}
|
||||
|
||||
// Public variant used by blog: allow access if the image's folder is visible to 'everyone'.
|
||||
async getImageFilePathPublicByHash(hash) {
|
||||
const image = await Image.findOne({ where: { hash } });
|
||||
@@ -510,7 +810,7 @@ class SocialNetworkService extends BaseService {
|
||||
async changeImage(hashedUserId, imageId, title, visibilities) {
|
||||
const userId = await this.checkUserAccess(hashedUserId);
|
||||
await this.checkUserImageAccess(userId, imageId);
|
||||
const image = await Image.findOne({ where: { id: imageId } });
|
||||
const image = await Image.findOne({ where: { id: imageId, isAdultContent: false } });
|
||||
if (!image) {
|
||||
throw new Error('image not found')
|
||||
}
|
||||
@@ -522,13 +822,33 @@ class SocialNetworkService extends BaseService {
|
||||
return image.folderId;
|
||||
}
|
||||
|
||||
async changeAdultImage(hashedUserId, imageId, title, visibilities) {
|
||||
const userId = await this.requireAdultAreaAccessByHash(hashedUserId);
|
||||
const image = await Image.findOne({
|
||||
where: {
|
||||
id: imageId,
|
||||
userId,
|
||||
isAdultContent: true
|
||||
}
|
||||
});
|
||||
if (!image) {
|
||||
throw new Error('image not found');
|
||||
}
|
||||
await image.update({ title });
|
||||
await ImageImageVisibility.destroy({ where: { imageId } });
|
||||
for (const visibility of visibilities) {
|
||||
await ImageImageVisibility.create({ imageId, visibilityTypeId: visibility.id });
|
||||
}
|
||||
return image.folderId;
|
||||
}
|
||||
|
||||
async getFoldersByUsername(username, hashedUserId) {
|
||||
const user = await this.loadUserByName(username);
|
||||
if (!user) {
|
||||
throw new Error('User not found');
|
||||
}
|
||||
const requestingUserId = await this.checkUserAccess(hashedUserId);
|
||||
let rootFolder = await Folder.findOne({ where: { parentId: null, userId: user.id } });
|
||||
let rootFolder = await Folder.findOne({ where: { parentId: null, userId: user.id, isAdultArea: false } });
|
||||
if (!rootFolder) {
|
||||
return null;
|
||||
}
|
||||
@@ -542,9 +862,9 @@ class SocialNetworkService extends BaseService {
|
||||
const folderIdString = String(folderId);
|
||||
const requestingUserIdString = String(requestingUserId);
|
||||
const requestingUser = await User.findOne({ where: { id: requestingUserIdString } });
|
||||
const isAdult = this.isUserAdult(requestingUser.id);
|
||||
const isAdult = await this.isUserAdult(requestingUser.id);
|
||||
const accessibleFolders = await Folder.findAll({
|
||||
where: { parentId: folderIdString },
|
||||
where: { parentId: folderIdString, isAdultArea: false },
|
||||
include: [
|
||||
{
|
||||
model: ImageVisibilityType,
|
||||
|
||||
Reference in New Issue
Block a user