unclean SPARC
This commit is contained in:
@@ -0,0 +1,251 @@
|
||||
class MailingExclusionDialog extends EICDialogContent {
|
||||
|
||||
actions = [
|
||||
{
|
||||
label: 'Cancel',
|
||||
onclick: this.cancel.bind(this),
|
||||
severity: 'secondary',
|
||||
role: 'cancel'
|
||||
},
|
||||
{
|
||||
label: 'Import & Exclude them',
|
||||
onclick: this.add.bind(this),
|
||||
severity: 'primary',
|
||||
role: 'add',
|
||||
disabled: true
|
||||
}
|
||||
]
|
||||
|
||||
constructor(...args) {
|
||||
super(...args)
|
||||
Object.assign(this, app.helpers.validators)
|
||||
}
|
||||
|
||||
DOMContentLoaded(options) {
|
||||
this.model = options.model
|
||||
this.mid = options.mid
|
||||
let components = ui.eicfy(this.el)
|
||||
this.fileUpload = new FileUpload(this.find('.import-dialog .browseBtn'), {
|
||||
uploadUrl: '#',
|
||||
uploadMethod: '',
|
||||
submitLabel:'Analyse file',
|
||||
allowedExtensions: ['xls','xlsx'],
|
||||
allowedMimes:['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'application/vnd.ms-excel'],
|
||||
allowDrop: true,
|
||||
maxFiles: 1,
|
||||
minFiles: 1,
|
||||
dndLabel: 'Drop your recipents Excel list here !',
|
||||
noUpload: true,
|
||||
});
|
||||
this.fileUpload.onFileAdded = this.onFileAdded.bind(this)
|
||||
this.fileUpload.onFileRemoved = this.onFileRemoved.bind(this)
|
||||
this.fileUpload.onWrongFileType = this.onWrongFileType.bind(this)
|
||||
this.report = this.find('.import-dialog .report')
|
||||
this.reportTitle = this.find('.import-dialog .report-title')
|
||||
this.reportDetails = this.find('.import-dialog .report-details')
|
||||
this.recipientsToImport = {}
|
||||
}
|
||||
onFileAdded(fileIdx, file){
|
||||
let reader = new FileReader()
|
||||
reader.onload = this.verifyData.bind(this, reader, file)
|
||||
this.fileUpload.browseBtn.loading = true
|
||||
reader.readAsArrayBuffer(file)
|
||||
}
|
||||
|
||||
onWrongFileType(file){
|
||||
ui.show(this.report)
|
||||
this.fileUpload.browseBtn.loading = false
|
||||
// because stopping the loading reactivates the button by default (god's will)
|
||||
if(this.fileUpload.filesList.length==0) this.fileUpload.browseBtn.disabled = false
|
||||
else this.fileUpload.browseBtn.disabled = true
|
||||
this.reportTitle.classList.add('error')
|
||||
this.reportTitle.innerHTML = `Could not import file !`
|
||||
this.reportDetails.innerHTML = `Wrong file type (${file.type})`
|
||||
}
|
||||
|
||||
verifyData(reader, file){
|
||||
this.fileUpload.browseBtn.loading = false
|
||||
// because stopping the loading reactivates the button by default (god's will)
|
||||
if(this.fileUpload.filesList.length==0) this.fileUpload.browseBtn.disabled = false
|
||||
else this.fileUpload.browseBtn.disabled = true
|
||||
let error
|
||||
let workbook = null
|
||||
let recipientsArray = null
|
||||
let recipientsList = null
|
||||
try{
|
||||
workbook = XLSX.read(reader.result)
|
||||
} catch(e) {
|
||||
console.warn('Trying to parse Excel file:',e)
|
||||
error = 'Error parsing this as Excel file !'
|
||||
}
|
||||
|
||||
if((!error) && workbook){
|
||||
let first_sheet = workbook.Sheets[workbook.SheetNames[0]]
|
||||
try{
|
||||
recipientsArray = XLSX.utils.sheet_to_json(first_sheet, {
|
||||
header: 1
|
||||
})
|
||||
} catch(e) {
|
||||
recipientsArray = null
|
||||
error = 'Error parsing this as Excel sheet !'
|
||||
}
|
||||
if(recipientsArray && (!first_sheet['!margins'])) {
|
||||
recipientsArray = null
|
||||
error = 'Could not parse this as Excel file !'
|
||||
}
|
||||
}
|
||||
let result = {}
|
||||
if(recipientsArray){
|
||||
result = this.getEmailRows(recipientsArray, file)
|
||||
}
|
||||
ui.show(this.report)
|
||||
|
||||
if(result.recipientsList){
|
||||
this.reportTitle.classList.remove('error')
|
||||
this.reportTitle.innerHTML = `Found ${result.recipientsList.length} emails to use as Excusion list!`
|
||||
let headersList = ''
|
||||
if(result.availableColumns.some(item => item.hint)){
|
||||
headersList = result.availableColumns.map(item=>item.hint).join(', ')
|
||||
}
|
||||
this.reportDetails.innerHTML = `
|
||||
<ul>
|
||||
<li>Column used for the emails: <span success>${result.emailColName}</span></li>
|
||||
<li><span success>${(result.rejectedRows.length>0) ? result.rejectedRows.length : 'No'}</span> ${ (result.rejectedRows.length==1) ? 'row was' : 'rows where' } rejected because column ${result.emailColName} did not contain an email.</li>
|
||||
<li>Removed <span success>${result.nbDups}</span> emails that ${result.nbDups.length>1 ? 'where duplicates' : 'was a duplicate'}
|
||||
</li>
|
||||
</ul>
|
||||
`
|
||||
this.recipientsToImport = result
|
||||
this.recipientsToImport.sourceName = file.name
|
||||
this.recipientsToImport.sourceType = 'Excel'
|
||||
} else {
|
||||
this.reportTitle.classList.add('error')
|
||||
this.reportTitle.innerHTML = error
|
||||
this.reportDetails.innerHTML = ``
|
||||
this.recipientsToImport = {}
|
||||
}
|
||||
|
||||
if(this.fileUpload.filesList.length==0) this.actions.find(o => o.role == 'add').button.disabled = true
|
||||
else this.actions.find(o => o.role == 'add').button.disabled = false
|
||||
}
|
||||
|
||||
getEmailRows(recipientsArray, file){
|
||||
if((!Array.isArray(recipientsArray)) || (recipientsArray.length<1)){
|
||||
return({
|
||||
err: 'The parsed Excel is not an array or has no rows !',
|
||||
recipientsList:[],
|
||||
importedData:[],
|
||||
rejectedRows: [],
|
||||
nbDups: 0,
|
||||
emailColIdx:null,
|
||||
emailColName:null,
|
||||
availableColumns: null,
|
||||
})
|
||||
}
|
||||
//const mailRFC5322Regex = /^([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22))*\x40([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d))*$/
|
||||
//Spot the column where there are the most email-addresses
|
||||
let colsCount = []
|
||||
for(let row of recipientsArray){
|
||||
let colIdx = 0
|
||||
for(let cell of row){
|
||||
if(typeof(cell) === null) cell = ''
|
||||
if(typeof(cell)=='string'){
|
||||
if(typeof(colsCount[colIdx])=='undefined') colsCount[colIdx] = 0
|
||||
if(this.validators.isValidEmail(cell)) colsCount[colIdx]++
|
||||
}
|
||||
colIdx++
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup empty slots => don't use "in", or "of" !
|
||||
for(let idx=0; idx<colsCount.length; idx++){ if(typeof(colsCount[idx])!='number') colsCount[idx]=0 }
|
||||
// find winning column
|
||||
let emailCol = colsCount.reduce((acc,val, idx)=>(val>colsCount[acc]?idx:acc),0)
|
||||
|
||||
// Now that we know where to look, remove rows without email in that col
|
||||
let cleanRecipients = []
|
||||
let rejectedRows = []
|
||||
let firstValidRow = null
|
||||
let rowIdx = 1
|
||||
for(let row of recipientsArray){
|
||||
let cell = row[emailCol]
|
||||
if(typeof(cell)!='string'){
|
||||
rejectedRows.push(rowIdx)
|
||||
} else {
|
||||
if(this.validators.isValidEmail(cell)){
|
||||
cleanRecipients.push(row)
|
||||
if(!firstValidRow) firstValidRow = rowIdx
|
||||
}
|
||||
else rejectedRows.push(rowIdx)
|
||||
}
|
||||
rowIdx++
|
||||
}
|
||||
|
||||
// The row before the first valid email row might be headers
|
||||
let availableColumns
|
||||
if(firstValidRow>1){
|
||||
let headersRow = recipientsArray[firstValidRow-2] // rowIdx & firstValidRow start at 1 => row before the first valid is -2 in recipientsArray
|
||||
availableColumns = headersRow.map( (item, idx) => ({value: idx, hint: ((item.length > 150) ? item.slice(0, 20) + '...' : item ), isEmail: (idx==emailCol) }) )
|
||||
} else {
|
||||
availableColumns = recipientsArray[firstValidRow].map( (item, idx) => ({value: idx, hint: '', isEmail: (idx==emailCol) }) )
|
||||
}
|
||||
|
||||
let nodups=[]
|
||||
const uniqueRecipients = cleanRecipients.filter(item=>{ if(!nodups.includes(item[emailCol])) { nodups.push(item[emailCol]); return(true) } return(false) })
|
||||
|
||||
let finalRecipients = cleanRecipients
|
||||
|
||||
let recipientsList=[]
|
||||
for(let recipient of finalRecipients) {
|
||||
recipientsList.push({
|
||||
sourceType: "Excel",
|
||||
sourceName: file.name,
|
||||
email:recipient[emailCol],
|
||||
meta:{}, //Empty mappings
|
||||
})
|
||||
}
|
||||
|
||||
return({
|
||||
err: false,
|
||||
recipientsList: recipientsList,
|
||||
importedData: finalRecipients,
|
||||
rejectedRows: rejectedRows,
|
||||
nbDups: cleanRecipients.length - uniqueRecipients.length,
|
||||
emailColIdx: emailCol,
|
||||
emailColName: XLSX.utils.encode_col(emailCol),
|
||||
availableColumns: availableColumns,
|
||||
})
|
||||
}
|
||||
|
||||
onFileRemoved(fileIdx, file){
|
||||
if(this.fileUpload.filesList.length==0){ // normally the case as maxFiles=1
|
||||
this.reportTitle.innerHTML = ''
|
||||
this.reportDetails.innerHTML = ''
|
||||
ui.hide(this.report)
|
||||
this.recipientsToImport = {}
|
||||
this.actions.find(o => o.role == 'add').button.disabled = true
|
||||
} else {
|
||||
this.actions.find(o => o.role == 'add').button.disabled = false
|
||||
}
|
||||
}
|
||||
|
||||
async add() {
|
||||
this.actions.find(o => o.role == 'add').button.loading = true
|
||||
this.recipientsToImport.importDate = (new Date()).toISOString()
|
||||
await this.model.saveExclusion(this.mid, {
|
||||
sourceName: this.recipientsToImport.sourceName,
|
||||
sourceType: this.recipientsToImport.sourceType,
|
||||
data: this.recipientsToImport.importedData,
|
||||
availableColumns: this.recipientsToImport.availableColumns,
|
||||
})
|
||||
this.commit(true)
|
||||
}
|
||||
|
||||
onFailed() {
|
||||
this.abort()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
app.registerClass('MailingExclusionDialog',MailingExclusionDialog);
|
||||
Reference in New Issue
Block a user