/**
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ class Processor { private static processThread ( session_data , thread_data ) { for ( const message_data of thread_data . message_data_list ) { let min_stage = 0 ; let max_stage = Number . MAX_VALUE ; for ( const rule of session_data . rules ) { if ( rule . stage < min_stage ) { continue ; } if ( rule . stage > max_stage ) { break ; } if ( rule . condition . match ( message_data ) ) { console . log ( `rule ${ rule } matches message ${ message_data }, apply action ${ rule . thread_action }` ) ; thread_data . thread_action . mergeFrom ( rule . thread_action ) ; let endThread = false ; switch ( rule . thread_action . action_after_match ) { case ActionAfterMatchType . DONE : endThread = true ; break ; case ActionAfterMatchType . FINISH_STAGE : case ActionAfterMatchType . DEFAULT : max_stage = rule . stage ; break ; case ActionAfterMatchType . NEXT_STAGE : min_stage = rule . stage + 1 ; max_stage = Number . MAX_VALUE ; break ; } if ( endThread ) { break ; } } } console . log ( `Message is processed at stage ${ max_stage }` ) ; } thread_data . validateActions ( ) ; } public static processAllUnprocessedThreads ( ) { const start_time = new Date ( ) ; const session_data = new SessionData ( ) ; if ( ! session_data . rules ) { return ; } const unprocessed_threads = withTimer ( "fetchUnprocessedThreads" , ( ) => GmailApp . search ( 'label:' + session_data . config . unprocessed_label , 0 , session_data . config . max_threads ) ) ; Logger . log ( `Found ${ unprocessed_threads . length } unprocessed threads.` ) ; if ( ! unprocessed_threads ) { Logger . log ( `All emails are processed, skip.` ) ; return ; } const all_thread_data = withTimer ( "transformIntoThreadData" , ( ) => unprocessed_threads . map ( thread => new ThreadData ( session_data , thread ) ) ) ; let processed_thread_count = 0 , processed_message_count = 0 ; let all_pass = true ; withTimer ( "collectActions" , ( ) => { for ( const thread_data of all_thread_data ) { try { Processor . processThread ( session_data , thread_data ) ; processed_thread_count ++ ; processed_message_count += thread_data . message_data_list . length ; } catch ( e ) { all_pass = false ; console . error ( `Process email failed: ${ e }` ) ; Logger . log ( `Process email failed: ${ e }` ) ; thread_data . thread_action . move_to = InboxActionType . INBOX ; thread_data . thread_action . label_names . clear ( ) ; thread_data . thread_action . label_names . add ( session_data . config . processing_failed_label ) ; } } } ) ; Logger . log ( `Processed ${ processed_thread_count } out of ${ unprocessed_threads . length }.` ) ; withTimer ( "applyAllActions" , ( ) => ThreadData . applyAllActions ( session_data , all_thread_data ) ) ; withTimer ( 'addStatRecord' , ( ) => Stats . addStatRecord ( start_time , processed_thread_count , processed_message_count ) ) ; assert ( all_pass , `Some processing fails, check emails` ) ; } }