Skip to content
Permalink
Browse files
Merge 'origin/jeea2-image' into article-testing
  • Loading branch information
sarkarj committed Nov 27, 2019
2 parents 8939246 + 9ee909a commit 323cff96d43fae4a9b8a214b0fe9337b9355865b
Show file tree
Hide file tree
Showing 6 changed files with 489 additions and 0 deletions.
@@ -0,0 +1,2 @@
/node_modules
/docs
@@ -0,0 +1,135 @@
'use strict'

const sqlite = require('sqlite-async')

/**
* Class representing images in the database.
*/
class Image {

/**Constructs database with the appropriate table for article images.
* @constructor
* @param {string} [dbName=':memory:'] - database for the website
*/
constructor(dbName = ':memory:') {
return (async() => {
this.db = await sqlite.open(dbName)
const sql = `CREATE TABLE IF NOT EXISTS images (
id INTEGER PRIMARY KEY AUTOINCREMENT,
image_path TEXT,
image_description TEXT);`
await this.db.run(sql)
return this
})()
}

/**
* Adds filename of selected file to the database.
* @param {string} filename
* @param {string} [description]
* @returns {Promise<true>} confirmation for insertion of filename in database
*/
async add(filename, description) {
try{
if(filename.length === 0) throw new Error('filename is missing')
let sql = `SELECT COUNT(id) as records from images WHERE image_path = '${filename}';`
const data = await this.db.get(sql)
if(data.records !== 0) throw new Error('filename is already in use')
if(description === undefined) {
sql = `INSERT INTO images (image_path) values ('${filename}');`
await this.db.run(sql)
return true
} else {
sql = `INSERT INTO images (image_path, image_description) values ('${filename}', '${description}');`
await this.db.run(sql)
return true
}
} catch(err) {
throw err
}
}

/**
* Retrieves details of an image
* @param {Integer} key - id of the image
* @returns {Promise<imageData>}
*/
async get(key) {
try{
if(key === undefined) throw new Error('key is not defined')
let sql = `SELECT COUNT(id) as records FROM images WHERE id = ${key};`
let data = await this.db.get(sql)
if(data.records === 0) throw new Error('file does not exist')
sql = `SELECT image_path, image_description
FROM images WHERE id = ${key};`
data = await this.db.get(sql)
return data
} catch(err) {
throw err
}
}

/**
* Retrieves details of all stored images
* @returns {Promise<imageData[]>} - array of image data
*/
async getAll() {
const sql = `SELECT image_path as path,
image_description as description
FROM images;`
const data = await this.db.all(sql)
return data
}

/**
* Rename an existing file
* @param {string} targetFile - full path of file
* @param {string} newName - new filename
* @returns {Promise<true>} confirmation for file being renamed
*/
async rename(targetFile, newName) {
try{
if(targetFile.length === 0) throw new Error('file not selected')
if(newName.length === 0) throw new Error('new name not stated')
let sql = `SELECT COUNT(id) as records FROM images WHERE image_path = '${targetFile}';`
const data = await this.db.get(sql)
if(data.records === 0) throw new Error('file is not found')
sql = `UPDATE images SET image_path = '${newName}' WHERE image_path = '${targetFile}';`
await this.db.run(sql)
return true
} catch(err) {
throw err
}
}

/**
* Delete an exisitng image file based on image id
* @param {integer} key
* @returns {Promise<true>} confirmation for image deleted
*/
async delete(key) {
try{
if(key === undefined) throw new Error('key is not defined')
let sql = `SELECT COUNT(id) as records FROM images WHERE id = ${key};`
const data = await this.db.get(sql)
if(data.records === 0) throw new Error('file is not found')
sql = `DELETE FROM images WHERE id = ${key}`
await this.db.run(sql)
return true
} catch(err) {
throw err
}
}

/**
* Count the sum of images
* @returns {Promise<integer>} number representing amount of stored images
*/
async count() {
const sql = 'SELECT COUNT(id) as records FROM images'
const data = await this.db.get(sql)
return data.records
}
}

module.exports = Image
@@ -0,0 +1,68 @@
'use strict'

const fs = require('fs')
const util = require('util')
const mime = require('mime-types')

//util.promisify used to make convert callback functions to promises
const copy = util.promisify(fs.copyFile)
const unlink = util.promisify(fs.unlink)
const exists = util.promisify(fs.exists)

/**
* Allow users to upload images
* @param {string} path - path of file
* @param {string} mimeType - mime type of file
* @param {string} fileName
* @param {string} newPath - new path of file
* @returns {Promise<boolean>} true if no errors
*/
const uploadPicture = async(path, mimeType, fileName, newPath) => {
try{
if(path.length === 0) throw new Error('path is blank')
if(mimeType.length === 0) throw new Error('mimeType is blank')
const extension = mime.extension(mimeType)
const acceptedExtension = ['jpg', 'png', 'webp', 'tiff', 'gif', 'svg']
if(acceptedExtension.includes(extension) === false) throw new Error('file type is not suitable for upload')
const newFile = `${newPath}${fileName}.${extension}`
await copy(path, newFile)
return true
} catch(err) {
throw err
}
}

/**
* Delete an existing image file
* @param {string} targetFile - full path of an existing file
* @returns {Promise<boolean>} true if no errors
*/
const deletePicture = async(targetFile) => {
try{
if(await exists(`${targetFile}`) === false) throw new Error('image file does not exist')
await unlink(`${targetFile}`)
return true
} catch(err) {
throw err
}
}

/**
* Rename the image file
* @param {string} targetFile - full path of existing file
* @param {string} newName - new path for target file
* @returns {Promise<boolean>} true if no errors
*/
const renamePicture = async(targetFile, newName) => {
try{
if(await exists(`${targetFile}`) === false) throw new Error('file does not exist')
const name = String(newName)
await copy(`${targetFile}`, `${name}`)
await unlink(`${targetFile}`)
return true
} catch(err) {
throw err
}
}

module.exports = {uploadPicture, deletePicture, renamePicture}
@@ -0,0 +1,16 @@
/** @typedef {Object} userData
* @property {string} id
* @property {string} user - username
* @property {string} password
* @property {string} email
* @property {string} location
* @property {string} profileImg - profile picture
* @property {string} profileTxt - profile summary
* @property {string} registeredDate
*/

/**
* @typedef {imageData}
* @property {string} image_path
* @property {string} image_description
*/
@@ -0,0 +1,172 @@
'use strict'

const Image = require('../modules/image')

describe('add()', () => {
test('return error if filename is empty', async done => {
expect.assertions(1)
const image = await new Image()
await expect(image.add(''))
.rejects.toEqual(Error('filename is missing'))
done()
})

test('return error if filename exists in database', async done => {
expect.assertions(1)
const image = await new Image()
await image.add('public/avatars/adrian.png')
await expect(image.add('public/avatars/adrian.png'))
.rejects.toEqual(Error('filename is already in use'))
done()
})
test('add a single item', async done => {
expect.assertions(1)
const image = await new Image()
await image.add('public/avatars/adrian.png')
const count = await image.count()
expect(count).toEqual(1)
done()
})

test('add both filename and description to the database', async done => {
expect.assertions(2)
const image = await new Image()
const described = await image.add('public/avatars/adrian.png', 'Images of Adrian')
const count = await image.count()
expect(count).toEqual(1)
expect(described).toEqual(true)
done()
})
})

describe('get()', () => {
test('return error if parameters are not stated', async done => {
expect.assertions(1)
const image = await new Image()
await expect(image.get())
.rejects.toEqual(Error('key is not defined'))
done()
})

test('return error if file does not exist', async done => {
expect.assertions(1)
const image = await new Image()
await expect(image.get(1))
.rejects.toEqual(Error('file does not exist'))
done()
})

test('return the filename and description based on input', async done => {
expect.assertions(2)
const image = await new Image()
await image.add('public/avatars/adrian.png', 'Image of Adrian')
const result = await image.get(1)
expect(result.image_path).toEqual('public/avatars/adrian.png')
expect(result.image_description).toEqual('Image of Adrian')
done()
})
})
describe('getAll()', () => {

test('return empty array if there are no data stored', async done => {
expect.assertions(1)
const image = await new Image()
const results = await image.getAll()
expect(results).toEqual([])
done()
})

test('return all image filenames and descriptions', async done => {
expect.assertions(2)
const image = await new Image()
await image.add('public/avatars/adrian.png', 'Image of Adrian')
const results = await image.getAll()
expect(results[0].path).toEqual('public/avatars/adrian.png')
expect(results[0].description).toEqual('Image of Adrian')
done()
})
})

describe('rename()', () => {

test('return error if filename is empty', async done => {
expect.assertions(1)
const image = await new Image()
await expect(image.rename('', 'public/avatars/adrian.png'))
.rejects.toEqual(Error('file not selected'))
done()
})

test('return error if new name is empty', async done => {
expect.assertions(1)
const image = await new Image()
await expect(image.rename('public/avatars/adrian.png', ''))
.rejects.toEqual(Error('new name not stated'))
done()
})

test('return true when image_path is renamed', async done => {
expect.assertions(1)
const image = await new Image()
await image.add('public/avatars/adrian.png')
const renamed = await image.rename('public/avatars/adrian.png', 'public/avatars/adrian1.png')
expect(renamed).toEqual(true)
done()
})

test('return error when image_path is not found', async done => {
expect.assertions(1)
const image = await new Image()
await expect( image.rename('public/avatars/adrian.png', 'public/avatars/adrian1.png'))
.rejects.toEqual(Error('file is not found'))
done()
})
})

describe('delete()', () => {

test('return error when file id is not defined', async done => {
expect.assertions(1)
const image = await new Image()
await expect(image.delete())
.rejects.toEqual(Error('key is not defined'))
done()
})

test('return error when file id does not exist', async done => {
expect.assertions(1)
const image = await new Image()
await expect(image.delete(1))
.rejects.toEqual(Error('file is not found'))
done()
})

test('delete a single item from database', async done => {
expect.assertions(1)
const image = await new Image()
await image.add('public/avatars/adrian.png')
const deleted = await image.delete(1)
expect(deleted).toEqual(true)
done()
})
})

describe('count()', () => {
test('return the amount of images in database', async done => {
expect.assertions(1)
const image = await new Image()
await image.add('public/avatars/adrian.png')
await image.add('public/avatars/adrian1.png')
const amount = await image.count()
expect(amount).toEqual(2)
done()
})

test('return zero if no images are stored', async done => {
expect.assertions(1)
const image = await new Image()
const amount = await image.count()
expect(amount).toEqual(0)
done()
})
})

0 comments on commit 323cff9

Please sign in to comment.