<commit_before>// This file is part of Indico.
// Copyright (C) 2002 - 2020 CERN
//
// Indico is free software; you can redistribute it and/or
// modify it under the terms of the MIT License; see the
// LICENSE file for more details.

import _ from 'lodash';
import {createSelector} from 'reselect';

import {Translate} from 'indico/react/i18n';

import {InitialRevisionState, FinalRevisionState} from '../../models';

function shouldCreateNewRevision({initialState, finalState}) {
  return (
    initialState.name === InitialRevisionState.needs_submitter_confirmation ||
    (initialState.name === InitialRevisionState.ready_for_review &&
      ![
        FinalRevisionState.accepted,
        FinalRevisionState.rejected,
        FinalRevisionState.replaced,
      ].includes(finalState.name))
  );
}

function createNewCustomItemFromRevision(revision, updates) {
  return {
    id: `custom-item-${revision.id}-${revision.createdDt}-${updates.state}`,
    createdDt: revision.createdDt,
    user: revision.submitter,
    custom: true,
    revisionId: revision.id,
    ...updates,
  };
}

export function processRevisions(revisions) {
  const newRevisions = [];
  let numberOfRevisions = 1;
  let items = [];
  let currRevision = null;

  for (const [index, _revision] of revisions.entries()) {
    const revision = {..._revision};
    const {initialState, finalState} = revision;
    if (!currRevision) {
      currRevision = revision;
      items = [...revision.comments];
    }

    if (initialState.name === InitialRevisionState.needs_submitter_confirmation) {
      const prevRevision = revisions[index - 1];
      revision.header = Translate.string(
        '{editorName} (editor) has made some changes to the paper',
        {editorName: prevRevision && prevRevision.editor ? prevRevision.editor.fullName : ''}
      );
    }

    if (finalState.name === FinalRevisionState.replaced) {
      const updatedRevision = revisions[index + 1];

      items.push(
        createNewCustomItemFromRevision(updatedRevision, {
          header: Translate.string('Revision has been replaced'),
          state: FinalRevisionState.replaced,
          html: revision.commentHtml,
        })
      );

      items = [...items, ...updatedRevision.comments];
    } else if (finalState.name === FinalRevisionState.accepted) {
      let header;
      if (
        revision.editor !== null &&
        initialState.name === InitialRevisionState.needs_submitter_confirmation
      ) {
        header = Translate.string('Editor has accepted after making some changes');
      } else if (initialState.name === InitialRevisionState.needs_submitter_confirmation) {
        header = Translate.string('Submitter has accepted proposed changes');
      } else {
        header = Translate.string('Revision has been accepted');
      }

      items.push(
        createNewCustomItemFromRevision(revision, {
          state: 'accepted',
          html: revision.commentHtml,
          header,
        })
      );
    } else if (finalState.name === FinalRevisionState.rejected) {
      items.push(
        createNewCustomItemFromRevision(revision, {
          header: Translate.string('Revision has been rejected'),
          state: 'rejected',
          html: revision.commentHtml,
        })
      );
    } else if (finalState.name === FinalRevisionState.needs_submitter_changes) {
      let header;
      if (initialState.name === InitialRevisionState.needs_submitter_confirmation) {
        header = Translate.string('Submitter rejected proposed changes');
      } else {
        header = Translate.string('Submitter has been asked to make some changes');
      }

      items.push(
        createNewCustomItemFromRevision(revision, {
          user: revisions[0].submitter,
          state: 'needs_submitter_changes',
          html: revision.commentHtml,
          header,
        })
      );
    } else if (finalState.name === FinalRevisionState.needs_submitter_confirmation) {
      items.push(
        createNewCustomItemFromRevision(revision, {
          user: revisions[0].submitter,
          header: Translate.string('Editor made some changes'),
          state: 'needs_submitter_confirmation',
          html: revision.commentHtml,
        })
      );
    }

    if (shouldCreateNewRevision(revision) || index === revisions.length - 1) {
      newRevisions.push({
        ..._.omit(currRevision, 'comments'),
        number: numberOfRevisions++,
        items,
      });
      currRevision = null;
    }
  }

  return newRevisions;
}

export const getDetails = state => (state.timeline ? state.timeline.details : null);
export const getNewDetails = state => (state.timeline ? state.timeline.newDetails : null);
export const isInitialEditableDetailsLoading = state =>
  state.timeline.loading && !state.timeline.details;
export const isTimelineOutdated = createSelector(
  getDetails,
  getNewDetails,
  (details, newDetails) => newDetails !== null && !_.isEqual(details, newDetails)
);
export const getTimelineBlocks = state => state.timeline.timelineBlocks;
export const getLastTimelineBlock = createSelector(
  getTimelineBlocks,
  blocks => blocks && blocks[blocks.length - 1]
);<commit_msg>Fix custom revision actions not always showing up<commit_after>// This file is part of Indico.
// Copyright (C) 2002 - 2020 CERN
//
// Indico is free software; you can redistribute it and/or
// modify it under the terms of the MIT License; see the
// LICENSE file for more details.

import _ from 'lodash';
import {createSelector} from 'reselect';

import {Translate} from 'indico/react/i18n';

import {InitialRevisionState, FinalRevisionState} from '../../models';

function shouldCreateNewRevision({initialState, finalState}) {
  return (
    initialState.name === InitialRevisionState.needs_submitter_confirmation ||
    (initialState.name === InitialRevisionState.ready_for_review &&
      ![
        FinalRevisionState.accepted,
        FinalRevisionState.rejected,
        FinalRevisionState.replaced,
      ].includes(finalState.name))
  );
}

function createNewCustomItemFromRevision(revision, updates) {
  return {
    id: `custom-item-${revision.id}-${revision.createdDt}-${updates.state}`,
    createdDt: revision.createdDt,
    user: revision.submitter,
    custom: true,
    revisionId: revision.id,
    ...updates,
  };
}

export function processRevisions(revisions) {
  const newRevisions = [];
  let numberOfRevisions = 1;
  let items = [];
  let currBlockIdx = -1;

  for (const [index, _revision] of revisions.entries()) {
    const revision = {..._revision};
    const {initialState, finalState} = revision;
    if (currBlockIdx === -1) {
      currBlockIdx = index;
      items = [...revision.comments];
    }

    if (initialState.name === InitialRevisionState.needs_submitter_confirmation) {
      const prevRevision = revisions[index - 1];
      revision.header = Translate.string(
        '{editorName} (editor) has made some changes to the paper',
        {editorName: prevRevision && prevRevision.editor ? prevRevision.editor.fullName : ''}
      );
    }

    if (finalState.name === FinalRevisionState.replaced) {
      const updatedRevision = revisions[index + 1];

      items.push(
        createNewCustomItemFromRevision(updatedRevision, {
          header: Translate.string('Revision has been replaced'),
          state: FinalRevisionState.replaced,
          html: revision.commentHtml,
        })
      );

      items = [...items, ...updatedRevision.comments];
    } else if (finalState.name === FinalRevisionState.accepted) {
      let header;
      if (
        revision.editor !== null &&
        initialState.name === InitialRevisionState.needs_submitter_confirmation
      ) {
        header = Translate.string('Editor has accepted after making some changes');
      } else if (initialState.name === InitialRevisionState.needs_submitter_confirmation) {
        header = Translate.string('Submitter has accepted proposed changes');
      } else {
        header = Translate.string('Revision has been accepted');
      }

      items.push(
        createNewCustomItemFromRevision(revision, {
          state: 'accepted',
          html: revision.commentHtml,
          header,
        })
      );
    } else if (finalState.name === FinalRevisionState.rejected) {
      items.push(
        createNewCustomItemFromRevision(revision, {
          header: Translate.string('Revision has been rejected'),
          state: 'rejected',
          html: revision.commentHtml,
        })
      );
    } else if (finalState.name === FinalRevisionState.needs_submitter_changes) {
      let header;
      if (initialState.name === InitialRevisionState.needs_submitter_confirmation) {
        header = Translate.string('Submitter rejected proposed changes');
      } else {
        header = Translate.string('Submitter has been asked to make some changes');
      }

      items.push(
        createNewCustomItemFromRevision(revision, {
          user: revisions[0].submitter,
          state: 'needs_submitter_changes',
          html: revision.commentHtml,
          header,
        })
      );
    } else if (finalState.name === FinalRevisionState.needs_submitter_confirmation) {
      items.push(
        createNewCustomItemFromRevision(revision, {
          user: revisions[0].submitter,
          header: Translate.string('Editor made some changes'),
          state: 'needs_submitter_confirmation',
          html: revision.commentHtml,
        })
      );
    }

    if (shouldCreateNewRevision(revision) || index === revisions.length - 1) {
      // From here on, a new revision block will be created
      newRevisions.push({
        ..._.omit(revisions[currBlockIdx], 'comments'),
        number: numberOfRevisions++,
        customActions: revision.customActions, // Use the actions from the latest revision in the block
        items,
      });
      currBlockIdx = -1;
    }
  }

  return newRevisions;
}

export const getDetails = state => (state.timeline ? state.timeline.details : null);
export const getNewDetails = state => (state.timeline ? state.timeline.newDetails : null);
export const isInitialEditableDetailsLoading = state =>
  state.timeline.loading && !state.timeline.details;
export const isTimelineOutdated = createSelector(
  getDetails,
  getNewDetails,
  (details, newDetails) => newDetails !== null && !_.isEqual(details, newDetails)
);
export const getTimelineBlocks = state => state.timeline.timelineBlocks;
export const getLastTimelineBlock = createSelector(
  getTimelineBlocks,
  blocks => blocks && blocks[blocks.length - 1]
);
{'fraction_non_alphanumeric': 0.1114999054284093, 'fraction_numerical': 0.0034991488556837527, 'mean_word_length': 3.033180778032037, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4154839', 'n_tokens_mistral': 3030, 'n_tokens_neox': 2865, 'n_words': 676}