photo-manager/lib/photos.js

683 lines
17 KiB
JavaScript

'use strict'
const fs = require( 'fs' )
, md5 = require( 'md5' )
, path = require( 'path' )
, gm = require( 'gm' )
, url = require( 'url' )
, range = require( 'range-2018.js' )
, DB = require( './db.js' )
, GetID = require( './get-id.js' )
, Now = require( './readable-timestamp.js' )
, Config = require( '../config.js' )
const Sizes =
exports.Sizes =
{ S : 200
, N : 490
, M : 800
, L : 1600
}
const SortAccounts = arrAccounts =>
arrAccounts
.filter( a => a && a.trim( ) )
.sort( ( a,b ) => b[ 0 ] == a[ 0 ]
? 'i' == a[ 0xA ]
: 'r' == a[ 0 ]
)
const getHashFromPhotoURL =
exports.getHashFromPhotoURL = PhotoURL =>
PhotoURL.match( /([^\/_]+)_?L\.jpg$/ )[ 1 ]
const PhotoHashmapToSQL =
exports.PhotoHashmapToSQL = PhotoHashmap =>
Object.keys( PhotoHashmap )
.map( k => `Photo_${ k } = "${ PhotoHashmap[ k ] }"` )
.join( ',' )
const SmallerSizes =
exports.SmallerSizes =
Object.keys( Sizes )
.filter( k => 'L' != k )
const HashOrNr =
exports.HashOrNr = Hash =>
( Hash
&& Hash.length
&& ( Hash.length > 2 )
)
? Hash + '_'
: Hash
const getURL =
exports.getURL = ({ SKU, Hash, Size, EXT }) =>
url.resolve
( Config.Paths.imgGlobal
, path.join
( './'
, GetID( SKU )
, HashOrNr( Hash ) + Size + ( EXT || '.jpg' )
)
)
const getFilepath =
exports.getFilepath = ({ SKU, Hash, Size, EXT }) =>
path.join
( Config.Paths.imgLocal
, GetID( SKU )
, HashOrNr( Hash ) + Size + ( EXT || '.jpg' )
)
const Resize =
exports.Resize = ({ SKU, Hash }) =>
new Promise( ( resolve, reject ) =>
{ SmallerSizes.forEach( ( Size, i, a ) =>
{ gm( getFilepath({ SKU, Hash, Size : 'L' }) )
.resize( Sizes[ Size ], Sizes[ Size ] )
.write( getFilepath({ SKU, Hash, Size }), err =>
{ if( err )
{ reject( err ) }
if( i == a.length - 1 )
{ resolve( true ) }
})
})
}).catch( err => console.error
( Now( )
, 'error resizing'
, '(Photos.Resize)'
, err
) )
const Convert_toBW = path =>
new Promise( ( resolve, reject ) =>
{ gm( path )
.colorspace( 'GRAY' )
.write( path, err =>
{ if( err )
{ console.error
( Now( )
, 'error converting #10 to BW'
, path
, err
)
reject( false )
}
resolve( true )
})
}).catch( err => console.error
( Now( )
, 'error converting #10 to BW'
, '(Photos.Convert_toBW)'
, err
) )
const Process =
exports.Process = ({ FilePath, SKU, Variant, Nr }) =>
new Promise( async ( resolve, reject ) =>
{ if( 10 == Nr )
{ console.info( Now( ), 'converting to BW...\n' )
await Convert_toBW( FilePath )
}
const Hash = md5( fs.readFileSync( FilePath ) )
try
{ fs.mkdirSync( path.join( Config.Paths.imgLocal, GetID( SKU ) ) ) }
catch( err )
{ console.info( 'dir', path.join( Config.Paths.imgLocal, GetID( SKU ) ), 'exist' ) }
fs.renameSync( FilePath, getFilepath({ SKU, Hash, Size : 'L' }) )
const Varinat_Exist = await DB.read(
{ table : 'Photos'
, where : `( SKU = "${ SKU }"
AND Variant = "${ Variant }"
)`
})
if( !Varinat_Exist || !Varinat_Exist.length )
{ await createVariant({ SKU, Variant }) }
await DB.update(
{ table : 'Photos'
, set : ` Photo_${ Nr } = "${ getURL({ SKU, Hash, Size : 'L' }) }"
, Need_update = TRUE
`
, where : `( SKU = "${ SKU }"
AND Variant = "${ Variant }"
)`
})
await Resize({ SKU, Hash })
resolve( true )
}).catch( err => console.error
( Now( )
, 'error processing'
, '(Photos.Process)'
, err
) )
const Renumber =
exports.Renumber = ({ SKU, Variant, OldNr, NewNr }) =>
new Promise( async ( resolve, reject ) =>
{ const OldHashmap = await getHashmap(
{ SKU
, Variant
, arrNumbers : range( 1,10 )
})
const Photo_toShift = OldHashmap[ OldNr ]
let newArr = Object
.keys( OldHashmap )
.map( k => OldHashmap[ k ] )
newArr.unshift( null )
newArr.splice( OldNr, 1 )
newArr.splice( NewNr, 0, Photo_toShift )
let NewHashmap = { }
range( 1,10 ).map( Nr =>
{ NewHashmap[ Nr ] = newArr[ Nr ] })
console.info
( Now( )
, 'Renumbering\n from :'
, OldHashmap
, 'to :'
, NewHashmap
)
const _res = await DB.update(
{ table : 'Photos'
, set : PhotoHashmapToSQL( NewHashmap )
+ ', Need_update = TRUE'
, where : `( SKU = "${ SKU }"
AND Variant = "${ Variant }"
)`
})
if( _res && _res.length )
{ resolve( true ) }
else
{ reject( _res ) }
}).catch( err => console.error
( Now( )
, 'error renumbering'
, '(Photos.Renumber)'
, err
) )
const URLoccurrences =
exports.URLoccurrences = ({ SKU, PhotoURL }) =>
new Promise( async ( resolve, reject ) =>
{ const Photos_EQ_URL = range( 1,11 )
.map( Nr => `Photo_${ Nr } = "${ PhotoURL }"` )
.join( ' OR ' )
const _req = await DB.read(
{ table : 'Photos'
, where : `( SKU = "${ SKU }"
AND ( ${ Photos_EQ_URL } )
)`
})
if( typeof _req == 'object' )
{ let Occurrences = 0
_req.forEach( V =>
{ for( Param in V )
{ Occurrences += ( V[ Param ] == PhotoURL ) }
})
resolve( Occurrences )
}
reject( false )
}).catch( err => console.error
( Now( )
, 'error getting finding occurrences of an URL'
, '(Photos.URLoccurrences)'
, err
) )
const deletePhotoFiles =
exports.deletePhotoFiles = ({ SKU, Hash }) =>
new Promise( async ( resolve, reject ) =>
{ if( !Hash )
{ console.error
( Now( )
, 'cant delete file, no Hash in params:'
, { SKU, Hash }
)
resolve( false )
return false
}
// check if filename exist anywhere else
if( 1 < ( await URLoccurrences(
{ SKU
, PhotoURL : getURL({ SKU, Hash })
})
)
)
{ resolve( false )
return false
}
console.log( 'removing file:', SKU + '/' + Hash )
Object.keys( Sizes ).map
( Size => fs.unlinkSync( getFilepath({ SKU, Hash, Size }) ) )
resolve( true )
}).catch( err => console.error
( Now( )
, 'error deleting files'
, '(Photos.deletePhotoFiles)'
, err
) )
const removeOne =
exports.removeOne = ({ SKU, Variant, Nr }) =>
new Promise( async ( resolve, reject ) =>
{ const HashMap_req = await getHashmap(
{ SKU
, Variant
, arrNumbers : [ Nr ]
})
const PhotoURL = HashMap_req[ Nr ]
, Hash = getHashFromPhotoURL( PhotoURL )
console.log({ SKU, Variant, Nr, PhotoURL, Hash })
console.log
( Now( )
, 'removing photo'
, '(Photos.removeOne):\n'
, { SKU, Variant, Nr }
)
if( 10 === Number( Nr ) )
{ DB.update(
{ table : 'Photos'
, set : `Photo_10 = ""`
, where : `( SKU = "${SKU}"
AND Variant = "${Variant}"
)`
})
}
else
{ const OldHashmap = await getHashmap(
{ SKU
, Variant
, arrNumbers : range( 1,10 ).filter( _Nr => _Nr >= Nr )
})
let NewHashmap = { }
Object.keys( OldHashmap )
.filter( _Nr => OldHashmap[ _Nr ] )
.forEach( _Nr =>
{ NewHashmap[ _Nr ] =
OldHashmap[ Number( _Nr ) + 1 ] || ''
})
await DB.update(
{ table : 'Photos'
, set : PhotoHashmapToSQL( NewHashmap )
, where : `( SKU = "${SKU}"
AND Variant = "${Variant}"
)`
})
}
resolve( await deletePhotoFiles({ SKU, Hash }) )
}).catch( err => console.error
( Now( )
, 'error removing one'
, '(Photos.removeOne)'
, err
) )
const getHashmap =
exports.getHashmap = ({ SKU, Variant, arrNumbers }) =>
new Promise( async ( resolve, reject ) =>
{ const _req = await DB.read(
{ table : 'Photos'
, columns : ( arrNumbers || range( 1,11 ) )
.map( Nr => `Photo_${ Nr } AS "${ Nr }"` )
.join( ',' )
, where : `( SKU="${SKU}"
AND Variant="${Variant}"
)`
})
if( _req.length && typeof _req == 'object' )
{ resolve( _req[ 0 ] ) }
reject( false )
}).catch( err => console.error
( Now( )
, 'error getting hashmap'
, '(Photos.getHashmap)'
, err
) )
const setDefaultVariant =
exports.setDefaultVariant = async ({ SKU, Variant, oldVarinatRenamedTo }) =>
{ const _req = await DB.read(
{ table : 'Photos'
, columns : 'SKU, Variant, Accounts'
, where : `SKU = "${ SKU }"`
})
if( !_req.length )
{ console.error
( Now( )
, 'no records of SKU'
, SKU
)
return false
}
let oldDefault = { Accounts :'' }
, newDefault = { Accounts :'' }
_req.forEach( V =>
{ if( '_default' == V.Variant )
{ oldDefault = V }
if( Variant == V.Variant )
{ newDefault = V }
})
newDefault.Accounts =
[ ...newDefault.Accounts.split( /[\r\n]+/g )
, ...oldDefault.Accounts.split( /[\r\n]+/g )
]
newDefault.Accounts = SortAccounts( newDefault.Accounts )
if( oldDefault.SKU )
{ await DB.update(
{ table : 'Photos'
, set : ` Variant = "${ oldVarinatRenamedTo }"
, Accounts = ""
`
, where : `( SKU = "${ SKU }"
AND Variant = "_default"
)`
})
}
await DB.update(
{ table : 'Photos'
, set : ` Variant = "_default"
, Accounts = "${ newDefault.Accounts.join('\n') }"
, Need_update = TRUE
`
, where : `( SKU = "${ SKU }"
AND Variant = "${ Variant }"
)`
})
console.log
( Now( )
, `variant "${ Variant }"`
, `of "${ SKU }" is now the default`
, '(Photos.setDefaultVariant)'
)
return true
}
const createVariant =
exports.createVariant = ({ SKU, Variant, CopyOf }) =>
new Promise( async ( resolve, reject ) =>
{ const _test = await DB.read(
{ table : 'Photos'
, where : `( SKU = "${ SKU }"
AND Variant = "${ Variant }"
)`
})
if( _test.length )
{ resolve( true )
return true
}
const _req = await DB.read(
{ table : 'Photos'
, where : `( SKU = "${ SKU }"
AND Variant = "${ CopyOf || '_default' }"
)`
})
console.log( _req && _req.length && _req[ 0 ]
|| 'err DB.read [Photos.createVariant]'
)
const Accounts
= '_default' == Variant
? Config.Accounts.join( '\n' )
: ''
await DB.create(
{ table : 'Photos'
, set :
` SKU = "${ SKU }"
, Variant = "${ Variant }"
, Need_update = TRUE
, Accounts = "${ Accounts }"
`
+ ( _req && _req.length
? `, Photo_10 = "${ _req[ 0 ].Photo_10 }"`
+ ( CopyOf
? `
, Photo_1 = "${ _req[ 0 ].Photo_1 }"
, Photo_2 = "${ _req[ 0 ].Photo_2 }"
, Photo_3 = "${ _req[ 0 ].Photo_3 }"
, Photo_4 = "${ _req[ 0 ].Photo_4 }"
, Photo_5 = "${ _req[ 0 ].Photo_5 }"
, Photo_6 = "${ _req[ 0 ].Photo_6 }"
, Photo_7 = "${ _req[ 0 ].Photo_7 }"
, Photo_8 = "${ _req[ 0 ].Photo_8 }"
, Photo_9 = "${ _req[ 0 ].Photo_9 }"
`
: '' )
: '' )
})
resolve( true )
}).catch( err => console.error
( Now( )
, 'error creating Variant'
, '(Photos.createVariant)'
, err
) )
const assignVariantToAccount =
exports.assignVariantToAccount = ({ SKU, Account, Variant }) =>
new Promise( async ( resolve, reject ) =>
{ const AccountsBefore = await DB.read(
{ table : 'Photos'
, columns : 'Variant, Accounts'
, where : `( SKU = "${ SKU }"
AND Accounts LIKE "%${ Account }%"
)`
})
if( AccountsBefore && AccountsBefore.length )
{ const PrevVariant = AccountsBefore[ 0 ].Variant
let arrAccountsToStay = AccountsBefore[ 0 ].Accounts.split(/[\r\n]+/g)
arrAccountsToStay.splice( arrAccountsToStay.indexOf(Account), 1)
console.log({ PrevVariant, arrAccountsToStay })
await DB.update(
{ table : 'Photos'
, set : `Accounts = "${ arrAccountsToStay.join('\n') }"`
, where : `( SKU = "${ SKU }"
AND Variant = "${ PrevVariant }"
)`
})
}
else
{ console.warn(Account, 'was unset before') }
const AccountsInsertBefore = await DB.read(
{ table : 'Photos'
, columns : 'Accounts'
, set : `Accounts = "${ Account }"`
, where : `( SKU = "${ SKU }"
AND Variant = "${ Variant }"
)`
})
if( AccountsInsertBefore && AccountsInsertBefore.length )
{ let arrUpdatedAccountsInsert =
AccountsInsertBefore[ 0 ]
.Accounts
.split(/[\r\n]+/g)
arrUpdatedAccountsInsert.push(Account)
arrUpdatedAccountsInsert = SortAccounts( arrUpdatedAccountsInsert )
DB.update(
{ table : 'Photos'
, set : ` Accounts = "${ arrUpdatedAccountsInsert.join('\n') }"
, Need_update = TRUE
`
, where : `( SKU = "${ SKU }"
AND Variant = "${ Variant }"
)`
})
resolve( true )
}
else
{ reject( 'error getting AccountsInsertBefore' ) }
}).catch( err => console.error
( Now( )
, 'cant assign Variant to Account'
, '(Photos.assignVariantToAccount)'
, err
) )
const removeVariant =
exports.removeVariant = ({ SKU, Variant }) =>
new Promise( async ( resolve, reject ) =>
{ const VariantToDelete = await DB.read(
{ table : 'Photos'
, where : `( SKU = "${ SKU }"
AND Variant = "${ Variant }"
)`
})
if( !VariantToDelete.length )
{ resolve( 'variant does not exist' )
return true
}
if( VariantToDelete[ 0 ].Accounts.trim( ) )
{ const VariantsMigrateTo = await DB.read(
{ table : 'Photos'
, where : `( SKU = "${ SKU }"
AND Variant != "${ Variant }"
)`
})
if( VariantsMigrateTo.length )
{ let AccountsToMigrate = [...new Set
( [ ...VariantToDelete[ 0 ].Accounts.split( /[\r\n]+/g )
, ...VariantsMigrateTo[ 0 ].Accounts.split( /[\r\n]+/g )
]
)]
console.log(
{ VariantToDelete
, VariantsMigrateTo
, AccountsToMigrate
})
await DB.update(
{ table : 'Photos'
, set : `Accounts = "${ AccountsToMigrate.join('\n') }"`
, where : `( SKU = "${ SKU }"
AND Variant = "${ VariantsMigrateTo[ 0 ].Variant }"
)`
})
}
}
DB.delete(
{ table : 'Photos'
, where : `( SKU = "${ SKU }"
AND Variant = "${ Variant }"
)`
})
let Photos_toDelete = await getHashmap({ SKU, Variant })
if( Photos_toDelete )
{ for( let i=1; i<11; i++ )
{ if( Photos_toDelete[ i ] )
{ await deletePhotoFiles(
{ SKU
, Hash : Photos_toDelete[ i ]
})
}
}
}
resolve( true )
}).catch( err => console.error
( Now( )
, 'error removing variant'
, '(Photos.removeVariant)'
, err
) )
const readTable =
exports.readTable = table =>
new Promise( async ( resolve, reject ) =>
resolve( await DB.read({ table }) )
).catch( err => console.error
( Now( )
, 'error removing variant'
, '(Photos.readTable)'
, err
) )
const get_Photos_Since =
exports.get_Photos_Since = ( since = 0 ) =>
new Promise( async ( resolve, reject ) =>
{ const res = await DB.read(
{ table : 'Photos_Ordered'
, where : ( 0 != since )
&& `( Updated > "${ since }"
AND Updated IS NOT NULL
)`
|| '1'
, order_by : 'id'
}).catch( reject )
// console.log( 'get_Photos_Since:', since )
// console.log( 'res:', res )
resolve( res )
}).catch( err => console.error
( Now( )
, 'error removing variant'
, '(Photos.readTable)'
, err
) )
module.exports = exports