"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.processActivityPubCleaner = void 0;
const tslib_1 = require("tslib");
const bluebird_1 = require("bluebird");
const activitypub_1 = require("../../../helpers/activitypub");
const activity_1 = require("../../../helpers/custom-validators/activitypub/activity");
const video_comments_1 = require("../../../helpers/custom-validators/activitypub/video-comments");
const requests_1 = require("../../../helpers/requests");
const constants_1 = require("../../../initializers/constants");
const redis_1 = require("../../redis");
const video_1 = require("../../../models/video/video");
const video_comment_1 = require("../../../models/video/video-comment");
const video_share_1 = require("../../../models/video/video-share");
const logger_1 = require("../../../helpers/logger");
const account_video_rate_1 = require("../../../models/account/account-video-rate");
const lTags = (0, logger_1.loggerTagsFactory)('ap-cleaner');
function processActivityPubCleaner(_job) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        logger_1.logger.info('Processing ActivityPub cleaner.', lTags());
        {
            const rateUrls = yield account_video_rate_1.AccountVideoRateModel.listRemoteRateUrlsOfLocalVideos();
            const { bodyValidator, deleter, updater } = rateOptionsFactory();
            yield (0, bluebird_1.map)(rateUrls, (rateUrl) => (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
                const result = yield updateObjectIfNeeded({ url: rateUrl, bodyValidator, updater, deleter });
                if ((result === null || result === void 0 ? void 0 : result.status) === 'deleted') {
                    const { videoId, type } = result.data;
                    yield video_1.VideoModel.updateRatesOf(videoId, type, undefined);
                }
            }), { concurrency: constants_1.AP_CLEANER.CONCURRENCY });
        }
        {
            const shareUrls = yield video_share_1.VideoShareModel.listRemoteShareUrlsOfLocalVideos();
            const { bodyValidator, deleter, updater } = shareOptionsFactory();
            yield (0, bluebird_1.map)(shareUrls, (shareUrl) => (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
                yield updateObjectIfNeeded({ url: shareUrl, bodyValidator, updater, deleter });
            }), { concurrency: constants_1.AP_CLEANER.CONCURRENCY });
        }
        {
            const commentUrls = yield video_comment_1.VideoCommentModel.listRemoteCommentUrlsOfLocalVideos();
            const { bodyValidator, deleter, updater } = commentOptionsFactory();
            yield (0, bluebird_1.map)(commentUrls, (commentUrl) => (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
                yield updateObjectIfNeeded({ url: commentUrl, bodyValidator, updater, deleter });
            }), { concurrency: constants_1.AP_CLEANER.CONCURRENCY });
        }
    });
}
exports.processActivityPubCleaner = processActivityPubCleaner;
function updateObjectIfNeeded(options) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        const { url, bodyValidator, updater, deleter } = options;
        const on404OrTombstone = () => (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
            logger_1.logger.info('Removing remote AP object %s.', url, lTags(url));
            const data = yield deleter(url);
            return { status: 'deleted', data };
        });
        try {
            const { body } = yield (0, requests_1.doJSONRequest)(url, { activityPub: true });
            if (!body || !body.id || !bodyValidator(body))
                throw new Error(`Body or body id of ${url} is invalid`);
            if (body.type === 'Tombstone') {
                return on404OrTombstone();
            }
            const newUrl = body.id;
            if (newUrl !== url) {
                if ((0, activitypub_1.checkUrlsSameHost)(newUrl, url) !== true) {
                    throw new Error(`New url ${newUrl} has not the same host than old url ${url}`);
                }
                logger_1.logger.info('Updating remote AP object %s.', url, lTags(url));
                const data = yield updater(url, newUrl);
                return { status: 'updated', data };
            }
            return null;
        }
        catch (err) {
            if (err.statusCode === 404) {
                return on404OrTombstone();
            }
            logger_1.logger.debug('Remote AP object %s is unavailable.', url, lTags(url));
            const unavailability = yield redis_1.Redis.Instance.addAPUnavailability(url);
            if (unavailability >= constants_1.AP_CLEANER.UNAVAILABLE_TRESHOLD) {
                logger_1.logger.info('Removing unavailable AP resource %s.', url, lTags(url));
                return on404OrTombstone();
            }
            return null;
        }
    });
}
function rateOptionsFactory() {
    return {
        bodyValidator: (body) => (0, activity_1.isLikeActivityValid)(body) || (0, activity_1.isDislikeActivityValid)(body),
        updater: (url, newUrl) => (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
            const rate = yield account_video_rate_1.AccountVideoRateModel.loadByUrl(url, undefined);
            rate.url = newUrl;
            const videoId = rate.videoId;
            const type = rate.type;
            yield rate.save();
            return { videoId, type };
        }),
        deleter: (url) => (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
            const rate = yield account_video_rate_1.AccountVideoRateModel.loadByUrl(url, undefined);
            const videoId = rate.videoId;
            const type = rate.type;
            yield rate.destroy();
            return { videoId, type };
        })
    };
}
function shareOptionsFactory() {
    return {
        bodyValidator: (body) => (0, activity_1.isAnnounceActivityValid)(body),
        updater: (url, newUrl) => (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
            const share = yield video_share_1.VideoShareModel.loadByUrl(url, undefined);
            share.url = newUrl;
            yield share.save();
            return undefined;
        }),
        deleter: (url) => (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
            const share = yield video_share_1.VideoShareModel.loadByUrl(url, undefined);
            yield share.destroy();
            return undefined;
        })
    };
}
function commentOptionsFactory() {
    return {
        bodyValidator: (body) => (0, video_comments_1.sanitizeAndCheckVideoCommentObject)(body),
        updater: (url, newUrl) => (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
            const comment = yield video_comment_1.VideoCommentModel.loadByUrlAndPopulateAccountAndVideo(url);
            comment.url = newUrl;
            yield comment.save();
            return undefined;
        }),
        deleter: (url) => (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
            const comment = yield video_comment_1.VideoCommentModel.loadByUrlAndPopulateAccountAndVideo(url);
            yield comment.destroy();
            return undefined;
        })
    };
}
//# sourceMappingURL=activitypub-cleaner.js.map