Finds every record for one person, shows exactly what it found, and erases it only after a person approves.
Uses
Airtable
Slack
Handle a data erasure request, with approval
Whenever someone posts the erase command with an email address in the Slack channel you nominate, the workflow searches your Airtable table for every record with that address, replies in the thread with what it found, and asks for approval, by email and in Lodol, before deleting anything. Nothing is deleted until a person approves it, and a request that is rejected or left to run out deletes nothing.
Your deletion log gets a row recording what was requested, by whom, which table was searched, how many records matched and their IDs. It is written before any deletion and updated afterwards with who approved or rejected it and what was erased, and the outcome is posted in the thread. Matching is on the whole address, so one person's address never catches another's. A request with no valid address is refused, as is one matching more records than a run may delete.
Before the first run you need an Airtable records table with an 'Email' column and a log table with 'Name' and 'Notes' columns.
request.When someone types “erase” in a channel. Save it as request.airtableBaseId to blank.Set airtableBaseId to blank.recordsTable to blank.Set recordsTable to blank.deletionLogTable to blank.Set deletionLogTable to blank.maxRecordsPerRequest to 25.Set maxRecordsPerRequest to 25.requestedBySlackUser to request.user_id.Set requestedBySlackUser to request.user_id.requestChannel to request.channel_id.Set requestChannel to request.channel_id.requestMessageTs to request.message_ts.Set requestMessageTs to request.message_ts.emailAddress to blank.Set emailAddress to blank.identifierErrorIf a step below fails, save the error as identifierErrorrequest.arguments lowercase and save it as emailAddress.Make request.arguments lowercase and save it as emailAddress.emailAddress is emptyIf emailAddress is emptyemailAddress is a valid email address is noIf emailAddress is a valid email address is noemailAddress contains ' or emailAddress contains \If emailAddress contains ' or emailAddress contains \searchFormula to LOWER({Email}) = '@emailAddress'.Set searchFormula to LOWER({Email}) = '@emailAddress'.searchLimit to maxRecordsPerRequest multiplied by 1 plus 1.Set searchLimit to maxRecordsPerRequest multiplied by 1 plus 1.recordsTable. Save it as searchResult.List records in recordsTable. Save it as searchResult.matchedRecordIds to an empty list.Set matchedRecordIds to an empty list.unreadableRecords to 0.Set unreadableRecords to 0.record in searchResult.records:For each record in searchResult.records:recordErrorIf a step below fails, save the error as recordErrorrecord.fields.Email lowercase and save it as recordEmail.Make record.fields.Email lowercase and save it as recordEmail.recordEmail is emailAddressIf recordEmail is emailAddressrecord.id to the end of matchedRecordIds and save it as matchedRecordIds.Add record.id to the end of matchedRecordIds and save it as matchedRecordIds.unreadableRecords.Add 1 to unreadableRecords.matchedRecordIds and save it as matchCount.Count the items in matchedRecordIds and save it as matchCount.matchedRecordIds with , and save it as matchedIdList.Join matchedRecordIds with , and save it as matchedIdList.matchCount is 0If matchCount is 0requestChannel.Reply in a thread in requestChannel.
Reply To: requestMessageTsNo records match emailAddress in the recordsTable table, so there is nothing to erase. Nothing was deleted.matchCount multiplied by 1 is greater than maxRecordsPerRequest multiplied by…If matchCount multiplied by 1 is greater than maxRecordsPerRequest multiplied by…requestChannel.Reply in a thread in requestChannel.
Reply To: requestMessageTsRefusing this erase request. emailAddress matches matchCount records, which is more than the limit of maxRecordsPerRequest set on the 'maxRecordsPerRequest' step. Nothing was deleted. Check the request is right before raising the limit.foundSummary to Erasure request for emailAddressSet foundSummary to Erasure request for emailAddress
Found matchCount record(s) in the recordsTable table.foundDetail to Matched on a whole-address, case-insensitive match of the Email column.Set foundDetail to Matched on a whole-address, case-insensitive match of the Email column.
Record ids: matchedIdList
Records skipped because their Email could not be read: unreadableRecords.requestChannel.Reply in a thread in requestChannel.
Reply To: requestMessageTsfoundSummary
foundDetail
Nothing has been deleted. This run is now waiting for a person to approve the erasure in Lodol.logRequestLine to Requested by Slack user requestedBySlackUser in channel requestChannel (message requestMessageTs).Set logRequestLine to Requested by Slack user requestedBySlackUser in channel requestChannel (message requestMessageTs).logSearchLine to Identifier requested: emailAddressSet logSearchLine to Identifier requested: emailAddress
Searched table: recordsTable in base airtableBaseId
Match rule: whole-address, case-insensitive match on the Email column.logOpening to logRequestLineSet logOpening to logRequestLine
logSearchLine.logFindings to logOpeningSet logFindings to logOpening
foundDetail
Written before any deletion. Status at this point: awaiting approval, nothing erased.deletionLogTable. Save it as deletionRecord.Add a record to deletionLogTable. Save it as deletionRecord.deletionRecordId to deletionRecord.id.Set deletionRecordId to deletionRecord.id.approvalHeader to Requested by Slack user requestedBySlackUser in channel requestChannel.Set approvalHeader to Requested by Slack user requestedBySlackUser in channel requestChannel.approvalBody to Erase every record for: emailAddressSet approvalBody to Erase every record for: emailAddress
Airtable base: airtableBaseId
Table: recordsTable
foundDetail.approvalFooter to Approving permanently deletes these matchCount record(s) and cannot be undone. Rejecting it, or leaving it until the request runs out, cancels the request and deletes nothing.Set approvalFooter to Approving permanently deletes these matchCount record(s) and cannot be undone. Rejecting it, or leaving it until the request runs out, cancels the request and deletes nothing.approvalDetails to approvalHeaderSet approvalDetails to approvalHeader
approvalBody
approvalFooter.matchCount record(s) for emailAddress? Save it as erasureReview.Request approval: Permanently erase matchCount record(s) for emailAddress? Save it as erasureReview.approvalDetailsdecidedBy to not recorded.Set decidedBy to not recorded.deciderErrorIf a step below fails, save the error as deciderErrorerasureReview.decided_by.email and save it as deciderEmail.Trim erasureReview.decided_by.email and save it as deciderEmail.erasureReview.decided_by.name and save it as deciderName.Trim erasureReview.decided_by.name and save it as deciderName.deciderEmail isn't emptyIf deciderEmail isn't emptydecidedBy to deciderEmail.Change decidedBy to deciderEmail.deciderName isn't emptyIf deciderName isn't emptydecidedBy to deciderName (deciderEmail).Change decidedBy to deciderName (deciderEmail).decidedBy to deciderName.Change decidedBy to deciderName.The approval did not say who decided it, so the deletion record says 'not recorded'..Show in the output: The approval did not say who decided it, so the deletion record says 'not recorded'..reviewNote to blank.Set reviewNote to blank.erasureReview.comment isn't blankIf erasureReview.comment isn't blankreviewNote to Change reviewNote to
Note from the approval: erasureReview.comment.erasedIds to an empty list.Set erasedIds to an empty list.failedIds to an empty list.Set failedIds to an empty list.outcome to blank.Set outcome to blank.erasureReview.approved is yesIf erasureReview.approved is yesrecordId in matchedRecordIds:For each recordId in matchedRecordIds:deleteError If a step below fails, save the error as deleteErrorrecordId from recordsTable.Delete recordId from recordsTable.recordId to the end of erasedIds and save it as erasedIds.Add recordId to the end of erasedIds and save it as erasedIds.recordId to the end of failedIds and save it as failedIds.Add recordId to the end of failedIds and save it as failedIds.outcome to APPROVED and erased by decidedBy.Change outcome to APPROVED and erased by decidedBy.
Records erased: the length of erasedIds of matchCount
Erased ids: erasedIds joined by ,
Could not be erased: failedIds joined by , @reviewNote.outcome to NO DECISION: the approval request ran out before anyone decided, so nothing was erased. The matchCount matching record(s) are untouched.Change outcome to NO DECISION: the approval request ran out before anyone decided, so nothing was erased. The matchCount matching record(s) are untouched.outcome to DECLINED at the approval step by decidedBy. Nothing was erased. The matchCount matching record(s) are untouched.@reviewNote.Change outcome to DECLINED at the approval step by decidedBy. Nothing was erased. The matchCount matching record(s) are untouched.@reviewNote.logUpdateErrorIf a step below fails, save the error as logUpdateErrordeletionRecordId in deletionLogTable.Update deletionRecordId in deletionLogTable.logUpdateError as text.Show in the output: Could not close the deletion record: logUpdateError as text.requestChannel.Reply in a thread in requestChannel.
Reply To: requestMessageTsErasure request for emailAddress
outcome