import * as moment from 'moment' ; import * as Redux from 'redux' ; import { changeInstallStateAction , setMessageAction , setValueAction , toggleValueAction , updateAdminOptionsAction , updateLocalOptionAction , updateSyncStatusAction , } from '../actions' ; import { DisqusApi } from '../DisqusApi' ; import { IAdminOptions } from '../reducers/AdminOptions' ; import { InstallationState , } from '../reducers/AdminState' ; import { createRandomToken } from '../utils' ; import WordPressCommentExporter from '../WordPressCommentExporter' ; import { IRestResponse , WordPressRestApi , } from '../WordPressRestApi' ; import { Moment } from 'moment' ; const UPDATABLE_FIELDS = [ 'disqus_forum_url' , 'disqus_public_key' , 'disqus_secret_key' , 'disqus_admin_access_token' , 'disqus_sso_button' , 'disqus_sso_enabled' , 'disqus_sync_token' , 'disqus_render_js' , ] ; const valueFromInput = ( element ) : string => { const isCheckbox = element . type === 'checkbox' ; let value ; if ( isCheckbox ) value = element . checked ? '1' : '' ; else value = element . value ; return value ; } ; let syncedComments = 0 ; let totalSyncedComments = 0 ; const syncComments = async ( commentQueue , dispatch ) => { const maxParallelRequests = 100 ; const parallelRequests = [ ] ; for ( let comment of commentQueue ) { const requestPromise = WordPressRestApi . instance . pluginRestPostAsync ( 'sync/comment' , { object_type : 'post' , transformed_data : comment , verb : 'force_sync' , } , ( syncResponse ) => { const datestr = moment ( ) . format ( 'YYYY-MM-DD h:mm:ss a' ) ; dispatch ( updateSyncStatusAction ( { is_manual : true , progress_message : `Syncing ${ syncedComments } of ${ totalSyncedComments } comments` , last_message : `Manually synced comment "${ comment . id }" from Disqus: ${ datestr }` , } ) ) ; } ) . then ( ( ) => { parallelRequests . splice ( parallelRequests . indexOf ( requestPromise ) , 1 ) ; syncedComments += 1 ; } ) ; parallelRequests . push ( requestPromise ) ; if ( parallelRequests . length >= maxParallelRequests ) { await Promise . race ( parallelRequests ) ; } } Promise . all ( parallelRequests ) . then ( ( ) => { dispatch ( setValueAction ( 'isManualSyncRunning' , false ) ) ; dispatch ( updateSyncStatusAction ( { is_manual : true , progress_message : `Complete (${ syncedComments } of ${ totalSyncedComments })` , } ) ) ; } ) ; } ; const mapDispatchToProps = ( dispatch ) => { const handleClearMessage = ( event ) : void => { dispatch ( setMessageAction ( null ) ) ; } ; return { onCopyText : ( elementId ) : void => { try { const element = window . document . getElementById ( elementId ) as HTMLInputElement ; if ( element ) { element . select ( ) ; window . document . execCommand ( 'copy' ) ; } } catch ( err ) { } } , onDateSelectorInputchange : ( key , event ) : void => { const value = valueFromInput ( event . currentTarget ) ; dispatch ( setValueAction ( key , value ) ) ; } , onGenerateRandomSyncToken : ( event ) : void => { event . preventDefault ( ) ; const newToken = createRandomToken ( ) ; dispatch ( updateLocalOptionAction ( 'disqus_sync_token' , newToken ) ) ; } , onInputChange : ( key , event ) : void => { const value = valueFromInput ( event . currentTarget ) ; dispatch ( updateLocalOptionAction ( key , value ) ) ; } , onSubmitExportCommentsForm : ( event ) : void => { event . preventDefault ( ) ; const exporter = new WordPressCommentExporter ( dispatch ) ; exporter . startExportPosts ( ) ; } , onSubmitManualSyncForm : ( event ) => { event . preventDefault ( ) ; const rangeStartInput = event . currentTarget . elements . namedItem ( 'manualSyncRangeStart' ) as HTMLInputElement ; const rangeEndInput = event . currentTarget . elements . namedItem ( 'manualSyncRangeEnd' ) as HTMLInputElement ; const getDateFromInput = ( input ) => { const dateValue = input && input . value ; const timestamp = moment ( dateValue ) . endOf ( 'day' ) ; return timestamp ; } ; const startDate = getDateFromInput ( rangeStartInput ) ; const endDate = getDateFromInput ( rangeEndInput ) ; let commentQueue = [ ] ; const getDisqusComments = async ( cursor = '' ) => { return new Promise ( ( resolve , reject ) => { DisqusApi . instance . listPostsForForum ( cursor , startDate , endDate , 100 , async ( xhr ) => { let disqusData = null ; try { disqusData = JSON . parse ( ( xhr . target as XMLHttpRequest ) . responseText ) ; } catch ( error ) { } if ( ! disqusData || disqusData . code !== 0 ) { reject ( disqusData ) ; } else { dispatch ( updateSyncStatusAction ( { is_manual : true , progress_message : `Collecting ${ totalSyncedComments } comments` , last_message : null , } ) ) ; } const pendingComments = disqusData . response ; totalSyncedComments += pendingComments . length ; pendingComments . forEach ( ( comment ) => { commentQueue . push ( comment ) ; } ) ; const nextCursor = disqusData . cursor ; if ( nextCursor && nextCursor . hasNext ) { await getDisqusComments ( nextCursor . next ) ; } resolve ( commentQueue ) ; } ) ; } ) ; } ; dispatch ( setValueAction ( 'isManualSyncRunning' , true ) ) ; getDisqusComments ( ) . then ( ( commentQueue ) => { syncComments ( commentQueue , dispatch ) ; } ) . catch ( ( err ) => { dispatch ( setMessageAction ( { onDismiss : handleClearMessage , text : ( err && err . response ) || 'Error connecting to the Disqus API' , type : 'error' , } ) ) ; } ) ; } , onSubmitSiteForm : ( event ) => { event . preventDefault ( ) ; const fields = UPDATABLE_FIELDS . reduce ( ( previousValue , currentIdKey ) : any => { if ( currentIdKey in event . currentTarget . elements ) { const currentField = event . currentTarget . elements . namedItem ( currentIdKey ) ; const currentInputElement = currentField as HTMLInputElement ; const value = valueFromInput ( currentInputElement ) ; return ( Object as any ) . assign ( { [ currentInputElement . name ] : value , } , previousValue ) ; } return previousValue ; } , { } ) ; WordPressRestApi . instance . pluginRestPost ( 'settings' , fields , ( response ) : void => { if ( ! response ) return ; if ( response . code !== 'OK' ) { dispatch ( setMessageAction ( { onDismiss : handleClearMessage , text : response . message , type : 'error' , } ) ) ; return ; } dispatch ( updateAdminOptionsAction ( response . data ) ) ; dispatch ( setMessageAction ( { onDismiss : handleClearMessage , text : __ ( 'Changes saved successfully.' ) , type : 'success' , } ) ) ; dispatch ( toggleValueAction ( 'isSiteFormLocked' ) ) ; } ) ; } , onSubmitSyncConfigForm : ( event ) : void => { event . preventDefault ( ) ; const endpoint = event . currentTarget . name ; WordPressRestApi . instance . pluginRestPost ( endpoint , null , ( response ) : void => { if ( ! response ) return ; if ( response . code !== 'OK' ) { dispatch ( setMessageAction ( { onDismiss : handleClearMessage , text : response . message , type : 'error' , } ) ) ; return ; } dispatch ( updateSyncStatusAction ( response . data ) ) ; dispatch ( setMessageAction ( { onDismiss : handleClearMessage , text : __ ( 'Changes saved successfully.' ) , type : 'success' , } ) ) ; } ) ; } , onToggleState : ( key ) => { dispatch ( toggleValueAction ( key ) ) ; } , onUpdateInstallationState : ( newState ) => { dispatch ( changeInstallStateAction ( newState ) ) ; } , } ; } ; export { UPDATABLE_FIELDS } ; export default mapDispatchToProps ;