5180 fichiers 38.5 Mo 0 téléchargements 208 vues mis à jour il y a 5 heures ui
nitro-v36-with-renderer-v36 / src / api / guide-tool / GuardianChatReview.ts
GuardianChatReview.ts 15.4 Ko Télécharger le fichier
import { LocalizeText } from '../utils/LocalizeText';
import { localizeWithFallback } from '../utils/localizeWithFallback';

/**
 * The guardian's side of a bully report (AIR GuideSessionController, chat review states) and the
 * reporter's verdict (ChatReviewReporterFeedbackCtrl), as pure tables and parsers.
 */

/** Vote codes sent with ChatReviewGuideVote and read back in ChatReviewSessionResults. */
export const GUARDIAN_VOTE_OK = 0;
export const GUARDIAN_VOTE_BAD = 1;
export const GUARDIAN_VOTE_VERY_BAD = 2;
/** The result code of a review that ended without a verdict (forwarded to the moderators). */
export const GUARDIAN_VOTE_FORWARDED = -1;

/** ChatReviewSessionVotingStatus codes, which index the status tables below. */
export const GUARDIAN_STATUS_AWAITING_VOTE = 0;
export const GUARDIAN_STATUS_VOTED_OK = 1;
export const GUARDIAN_STATUS_VOTED_BAD = 2;
export const GUARDIAN_STATUS_VOTED_VERY_BAD = 3;
export const GUARDIAN_STATUS_NO_VOTE = 4;
export const GUARDIAN_STATUS_FINDING_NEW_VOTER = 5;

/** AIR `_r14af66d3bdfb9a`: the text and icon of a vote or a status. */
export const GUARDIAN_STATUS_KEYS = ['waiting', 'ok', 'bad', 'very_bad', 'refused', 'searching'];
/** AIR `_r9c27036690f7e4`: the text of the final verdict, where a refused vote reads "inconclusive". */
export const GUARDIAN_RESULT_KEYS = ['waiting', 'ok', 'bad', 'very_bad', 'inconclusive', 'searching'];

/** AIR `GuideSessionController.statusFromVote`. */
export const statusFromVote = (vote: number): number => {
    switch (vote) {
        case GUARDIAN_VOTE_OK:
            return GUARDIAN_STATUS_VOTED_OK;
        case GUARDIAN_VOTE_BAD:
            return GUARDIAN_STATUS_VOTED_BAD;
        case GUARDIAN_VOTE_VERY_BAD:
            return GUARDIAN_STATUS_VOTED_VERY_BAD;
        case GUARDIAN_VOTE_FORWARDED:
            return GUARDIAN_STATUS_NO_VOTE;
        default:
            return GUARDIAN_STATUS_AWAITING_VOTE;
    }
};

/** A status the official client animates (still waiting for a vote, or looking for a voter). */
export const isAnimatedStatus = (status: number): boolean => status === GUARDIAN_STATUS_AWAITING_VOTE || status === GUARDIAN_STATUS_FINDING_NEW_VOTER;

const statusKey = (status: number): string => GUARDIAN_STATUS_KEYS[status] ?? GUARDIAN_STATUS_KEYS[GUARDIAN_STATUS_AWAITING_VOTE];

export interface IChatReviewLine {
    /** 0 is the reported user, every other number an anonymous user of the room. */
    userIndex: number;
    messages: string[];
}

export interface IChatReviewRecord {
    /** When the incident happened, or null when the record carries no complete date. */
    incidentTime: Date | null;
    lines: IChatReviewLine[];
}

/**
 * AIR `setStateGuardianChatReviewVote`: the record starts with "y m d h min s;" and then has one
 * "unused;userIndex;message" line per chat line, separated by "\r". Consecutive lines of the same
 * user are joined into one entry.
 */
export const parseChatReviewRecord = (record: string): IChatReviewRecord => {
    const source = record ?? '';
    const separator = source.indexOf(';');
    const numbers = (separator >= 0 ? source.substring(0, separator) : '').match(/\d+/g) ?? [];

    const incidentTime =
        numbers.length > 5
            ? new Date(Number(numbers[0]), Number(numbers[1]) - 1, Number(numbers[2]), Number(numbers[3]), Number(numbers[4]), Number(numbers[5]))
            : null;

    const lines: IChatReviewLine[] = [];

    for (const line of source.split('\r')) {
        if (!line.length) continue;

        const first = line.indexOf(';');
        const second = first >= 0 ? line.indexOf(';', first + 1) : -1;

        if (second < 0) continue;

        const userIndex = Number(line.substring(first + 1, second));

        if (!Number.isFinite(userIndex)) continue;

        // AIR cuts at the third ";" (split(";", 3)); the message keeps everything up to there.
        const rest = line.substring(second + 1);
        const third = rest.indexOf(';');
        const message = third >= 0 ? rest.substring(0, third) : rest;
        const last = lines[lines.length - 1];

        if (last && last.userIndex === userIndex) {
            last.messages.push(message);
            continue;
        }

        lines.push({ userIndex, messages: [message] });
    }

    return { incidentTime, lines };
};

/** Seconds between the incident and `now`, what the "(x ago)" label shows; 0 without a date. */
export const secondsSinceIncident = (incidentTime: Date | null, now: number): number => {
    if (!incidentTime) return 0;

    return Math.max(0, Math.floor((now - incidentTime.getTime()) / 1000));
};

/** Every chat review text with the English the official client shipped. */
const GUARDIAN_TEXTS: Record<string, string> = {
    'guide.bully.request.guide.accept.title': 'Your help requests',
    'guide.bully.request.guide.accept.request.title': 'New request',
    'guide.bully.request.guide.accept.request.type': 'Bully report',
    'guide.bully.request.guide.accept.request.description':
        'A user has reported a case of bullying. Look at the anonymous chat log and vote on the case together with other Guardians.',
    'guide.bully.request.guide.accept.accept.button': 'Accept request',
    'guide.bully.request.guide.accept.skip.link': "I can't help with this request",
    'guide.bully.request.guide.vote.title': 'A bully report',
    'guide.bully.request.guide.vote.subtitle': 'THE INCIDENT',
    'guide.bully.request.guide.vote.waiting': 'Waiting for other Guardians to look at the case...',
    'guide.bully.request.guide.vote.question': 'How do you think the user behaved?',
    'guide.bully.request.guide.vote.ok': 'OK',
    'guide.bully.request.guide.vote.bad': 'Bully',
    'guide.bully.request.guide.vote.very_bad': 'SERIOUS',
    'guide.bully.request.guide.vote.ok.tooltip': 'Maybe a little annoying and pesky.',
    'guide.bully.request.guide.vote.bad.tooltip': "Very cruel and mean! That's not OK!",
    'guide.bully.request.guide.vote.very_bad.tooltip': 'Worse than bullying - let our moderation team know!',
    'guide.bully.request.guide.vote.close': "I can't decide based on this chat log",
    'guide.bully.request.guide.vote.perpetrator': 'SUSPECT',
    'guide.bully.request.guide.vote.anonymous': 'USER %ID%',
    'guide.bully.request.guide.results.title': 'Waiting for votes',
    'guide.bully.request.guide.results.waiting.title': 'Wait for the votes to come in.',
    'guide.bully.request.guide.results.waiting.description': 'The final verdict will be shown here as soon as enough votes have come in.',
    'guide.bully.request.guide.results.votes': 'THE VOTES SO FAR:',
    'guide.bully.request.guide.results.wait': "Thanks for your vote! You can close this window if you don't want to wait for the final result.",
    'guide.bully.request.guide.results.your_vote': 'YOUR VOTE',
    'guide.bully.request.guide.results.final.title': 'The final verdict',
    'guide.bully.request.guide.results.final.votes': 'THE FINAL VOTES:',
    'guide.bully.request.guide.results.thanks': 'Thanks for your vote!',
    'guide.bully.request.guide.results.outcome.waiting': 'Waiting for vote...',
    'guide.bully.request.guide.results.outcome.ok': 'Suspect behaved acceptably.',
    'guide.bully.request.guide.results.outcome.bad': 'Suspect behaved badly!',
    'guide.bully.request.guide.results.outcome.very_bad': 'Suspect behaved horribly!',
    'guide.bully.request.guide.results.outcome.refused': 'The Guardian did not vote.',
    'guide.bully.request.guide.results.outcome.inconclusive': 'This report has been forwarded to us.',
    'guide.bully.request.guide.results.outcome.searching': 'Looking for Guardians',
    'guide.bully.request.error.not_enough_guardians.title': 'Voting without result',
    'guide.bully.request.error.not_enough_guardians.heading': 'Not enough Guardians',
    'guide.bully.request.error.not_enough_guardians.message':
        'Your report could not be handled because there are not enough Guardians online. The report has been forwarded to us.',
    'guide.bully.request.reporter.title': 'Not so fast!',
    'guide.bully.request.reporter.note': 'Did you know you can also ignore another user by selecting them and clicking Tools -> Ignore?',
    'guide.bully.request.reporter.sent.caption': 'Your report has been sent.',
    'guide.bully.request.reporter.sent.body':
        'The Guardians have received your report and are looking at it.<br/><br/>You will get a separate confirmation when appropriate action has been taken.',
    'guide.bully.request.reporter.blocked.caption': "You can't send new reports.",
    'guide.bully.request.reporter.blocked.body':
        'Your reports have repeatedly been judged invalid by the Guardians, so you cannot send bully reports for a short while.',
    'guide.bully.request.reporter.blocked.note':
        'You can still ignore a bullying user by selecting them and clicking Tools -> Ignore, and in an emergency send a call for help to the Moderators.',
    'guide.bully.request.reporter.nochat.caption': 'Oops!',
    'guide.bully.request.reporter.nochat.body': "The Guardians can't vote on your case because the user you reported has not said anything.",
    'guide.bully.request.reporter.nochat.note':
        'If this is an emergency and you feel threatened by this user, you can still send a call for help to the Moderators.',
    'guide.bully.request.reporter.alreadyreported.caption': 'Oops!',
    'guide.bully.request.reporter.alreadyreported.body': 'Someone else has already reported this Habbo and the Guardians are looking at the case.',
    'guide.bully.request.reporter.alreadyreported.note':
        'If this is an emergency and you feel threatened by this Habbo, you can still send a call for help to the Moderators.',
    'guide.bully.request.reporter.tooquick.caption': 'Oops!',
    'guide.bully.request.reporter.tooquick.body': 'You used the help system recently, so you have to wait a moment before you can make a new request.',
    'guide.bully.request.reporter.tooquick.note':
        'If this is an emergency and you feel threatened by a user, you can still send a call for help to the Moderators.',
    'guide.bully.request.reporter.valid.caption': 'Thank you!',
    'guide.bully.request.reporter.valid.body':
        'Your report has been reviewed and appropriate action has been taken.<br/><br/>Thanks for helping us keep Habbo safe and fun for everyone!',
    'guide.bully.request.reporter.invalid.caption': "Don't misuse the bully reporting system.",
    'guide.bully.request.reporter.invalid.body':
        'Misusing the bully reporting system is punishable and will mean you temporarily cannot report new cases.<br/><br/>Read the Habbo Way if you want to refresh your memory about which behaviour is appropriate in Habbo.',
    'guide.pending.bully.title': 'Request pending',
    'guide.pending.bully.subtitle': 'Your previous request is still being reviewed',
    'guide.pending.bully.description': 'Our Guardians are still looking at your previous bully report. Wait until they are done.',
    'guide.pending.bully.report': 'YOUR CURRENT BULLY REPORT BEING HANDLED:',
    'guide.pending.bully.room': 'in room %ROOM%',
    'guide.pending.guide.title': 'Ongoing help case',
    'guide.pending.guide.subtitle': 'You have an ongoing help case',
    'guide.pending.guide.description': 'You have already accepted a request as a Helper and cannot send help requests of your own until it is resolved.',
    'guide.pending.tour.title': 'Ongoing tour',
    'guide.pending.tour.subtitle': 'You are still taking part in a tour',
    'guide.pending.tour.description': 'You are taking part in a tour right now and cannot send other help requests in the meantime.',
    'guide.pending.instructions.title': 'Request pending',
    'guide.pending.instructions.subtitle': 'Your previous request is still pending.',
    'guide.pending.instructions.description':
        'You are taking part in a tour or already have a question out. Wait until it is finished before you send a new request.',
    'guide.pending.instructions.report': 'YOUR CURRENT QUESTION BEING HANDLED:',
    'help.bully.title': 'Report a bully',
    'help.bully.subtitle': 'Someone is behaving badly?',
    'help.bully.description': 'Tell us who has been mean to you or bullied you.',
    'help.bully.submit': 'Report the selected user',
    'alert.close.button': 'Close'
};

/** A chat review text, in the hotel's language when it has one and in English otherwise. */
export const guardianText = (key: string, parameters: string[] = null, replacements: string[] = null): string => {
    let fallback = GUARDIAN_TEXTS[key] ?? key;

    if (parameters && replacements) {
        parameters.forEach((parameter, index) => {
            fallback = fallback.replace(new RegExp(`%${parameter}%`, 'gi'), () => replacements[index] ?? '');
        });
    }

    return localizeWithFallback(key, fallback, parameters, replacements);
};

/** The text of a vote or a status, e.g. "Suspect behaved badly!". */
export const guardianStatusText = (status: number): string => guardianText(`guide.bully.request.guide.results.outcome.${statusKey(status)}`);

/** The text of the final verdict, where a review without verdict reads "forwarded to us". */
export const guardianResultText = (status: number): string =>
    guardianText(`guide.bully.request.guide.results.outcome.${GUARDIAN_RESULT_KEYS[status] ?? GUARDIAN_RESULT_KEYS[0]}`);

/** The icon key of a vote or status ("ok", "very-bad", "waiting", ...) as the assets are named. */
export const guardianStatusIcon = (status: number): string => statusKey(status).replace('_', '-');

/**
 * ChatReviewReporterFeedbackCtrl.setText: the feedback window reads
 * guide.bully.request.reporter.<code>.<part> and falls back to guide.bully.request.reporter.<part>
 * when that code has no text of its own (only the note is shared).
 */
export const reporterFeedbackText = (code: string, part: 'caption' | 'body' | 'note'): string => {
    const specific = `guide.bully.request.reporter.${code}.${part}`;
    const localized = LocalizeText(specific);

    if (GUARDIAN_TEXTS[specific] || (localized && localized !== specific)) return guardianText(specific);

    return guardianText(`guide.bully.request.reporter.${part}`);
};

/**
 * AIR HelpController.showPendingTicket: which pending window a ticket opens ("guide" when the user
 * is the guide of it, otherwise by request type), or null for a type it has none for.
 */
export const pendingTicketWindow = (type: number, isGuide: boolean): string | null => {
    if (isGuide) return 'guide';

    switch (type) {
        case 0:
        case 2:
            return 'tour';
        case 1:
            return 'instructions';
        case 3:
            return 'bully';
        default:
            return null;
    }
};

/** GuideTicketCreationResult (class_4165.localizationCode). */
export const creationResultCode = (result: number): string => {
    switch (result) {
        case 0:
            return 'sent';
        case 1:
            return 'blocked';
        case 2:
            return 'nochat';
        case 3:
            return 'alreadyreported';
        default:
            return 'invalid';
    }
};

/** GuideTicketResolution (class_4059.localizationCode): guardians took action or forwarded is "valid". */
export const resolutionCode = (resolution: number): string => (resolution === 0 || resolution === 1 ? 'valid' : 'invalid');

/** GuideReportingStatus (class_2120.localizationCode) for the answers that refuse a report. */
export const reportingStatusCode = (status: number): string => {
    switch (status) {
        case 2:
            return 'blocked';
        case 3:
            return 'tooquick';
        default:
            return '';
    }
};
15Sujets
1Dépôts
20Membres
2En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser