import cloneDeep from 'lodash/cloneDeep'
import { create,
update,
deleteEntity,
fetch,
query,
upload,
parseData,
publish,
unpublish }
from '../../../entity'
import FormData from 'form-data'
import { createReadStream } from 'fs'
import error from '../../../core/contentstackError'
/**
* An entry is the actual piece of content created using one of the defined content types. Read more about <a href='https://www.contentstack.com/docs/guide/content-management'>Entries</a>.
* @namespace Entry
*/
export function Entry (http, data) {
this.stackHeaders = data.stackHeaders
this.content_type_uid = data.content_type_uid
this.urlPath = `/content_types/${this.content_type_uid}/entries`
if (data && data.entry) {
Object.assign(this, cloneDeep(data.entry))
this.urlPath = `/content_types/${this.content_type_uid}/entries/${this.uid}`
/**
* @description The Create an entry call creates a new entry for the selected content type.
* @memberof Entry
* @func update
* @param locale - Locale code to localized entry
* @returns {Promise<Entry.Entry>} Promise for Entry instance
* @example
* import * as contentstack from '@contentstack/management'
* const client = contentstack.client()
*
* client.stack({ api_key: 'api_key'}).contentType('content_type_uid').entry('uid').fetch()
* .then((entry) => {
* entry.title = 'My New Entry'
* entry.description = 'Entry description'
* return entry.update()
* })
* .then((entry) => console.log(entry))
*
* @example
* // To Localize Entry pass locale in parameter
* import * as contentstack from '@contentstack/management'
* const client = contentstack.client()
*
* client.stack({ api_key: 'api_key'}).contentType('content_type_uid').entry('uid').fetch()
* .then((entry) => {
* entry.title = 'My New Entry'
* entry.description = 'Entry description'
* return entry.update({ locale: 'en-at' })
* })
* .then((entry) => console.log(entry))
*
* @example
* // To update entry with asset field
* import * as contentstack from '@contentstack/management'
* const client = contentstack.client()
*
* client.stack({ api_key: 'api_key'}).contentType('content_type_uid').entry('uid').fetch()
* .then((entry) => {
* entry.title = 'My New Entry'
* entry.file = entry.file.uid // for single asset pass asset uid to entry asset field value
* entry.multiple_file = ['asset_uid_1', 'asset_uid_2'] // for multiple asset pass array of asset uid to entry asset field values
* return entry.update({ locale: 'en-at' })
* })
* .then((entry) => console.log(entry))
*
* @example
* // To update entry with reference field
* import * as contentstack from '@contentstack/management'
* const client = contentstack.client()
*
* client.stack({ api_key: 'api_key'}).contentType('content_type_uid').entry('uid').fetch()
* .then((entry) => {
* entry.title = 'My New Entry'
* entry.reference = entry.reference.uid // for single reference pass reference uid to entry reference field value
* entry.multiple_reference = ['reference_uid_1', 'reference_uid_2'] // for multiple reference pass array of reference uid to entry reference field values
* entry.multiple_content_type_reference = [{_content_type_uid: 'content_type_uid_1', uid: 'reference_uid_1'}, {_content_type_uid: 'content_type_uid_2', uid: 'reference_uid_2'}] // for multiple reference pass array of reference uid to entry reference field values
* return entry.update({ locale: 'en-at' })
* })
* .then((entry) => console.log(entry))
*/
this.update = update(http, 'entry')
/**
* @description The Delete an entry call is used to delete a specific entry from a content type.
* @memberof Entry
* @func delete
* @returns {Object} Response Object.
* @example
* import * as contentstack from '@contentstack/management'
* const client = contentstack.client()
*
* client.stack({ api_key: 'api_key'}).contentType('content_type_uid').entry('uid').delete()
* .then((response) => console.log(response.notice))
*/
this.delete = deleteEntity(http)
/**
* @description The fetch Entry call fetches Entry details.
* @memberof Entry
* @func fetch
* @param {Int} version Enter the version number of the entry that you want to retrieve. However, to retrieve a specific version of an entry, you need to keep the environment parameter blank.
* @param {Int} locale Enter the code of the language of which the entries need to be included. Only the entries published in this locale will be displayed.
* @param {Int} include_workflow Enter 'true' to include the workflow details of the entry.
* @param {Int} include_publish_details Enter 'true' to include the publish details of the entry.
* @returns {Promise<Entry.Entry>} Promise for Entry instance
* @example
* import * as contentstack from '@contentstack/management'
* const client = contentstack.client()
*
* client.stack({ api_key: 'api_key'}).contentType('content_type_uid').entry('uid').fetch()
* .then((entry) => console.log(entry))
*
*/
this.fetch = fetch(http, 'entry')
/**
* @description The Publish an asset call is used to publish a specific version of an asset on the desired environment either immediately or at a later date/time.
* @memberof Entry
* @func publish
* @returns {Promise<Object>} Response Object.
* @example
* import * as contentstack from '@contentstack/management'
* const client = contentstack.client()
*
* const entry = {
* "locales": [
* "en-us"
* ],
* "environments": [
* "development"
* ]
* }
*
* client.stack({ api_key: 'api_key'}).contentType('content_type_uid').entry('uid').publish({ publishDetails: entry, locale: "en-us", version: 1, scheduledAt: "2019-02-08T18:30:00.000Z"})
* .then((response) => console.log(response.notice))
*
*/
this.publish = publish(http, 'entry')
/**
* @description The Replace asset call will replace an existing asset with another file on the stack.
* @memberof Entry
* @func unpublish
* @returns {Promise<Object>} Response Object.
* @example
* import * as contentstack from '@contentstack/management'
* const client = contentstack.client()
*
* const entry = {
* "locales": [
* "en-us"
* ],
* "environments": [
* "development"
* ]
* }
*
* client.stack({ api_key: 'api_key'}).contentType('content_type_uid').entry('uid').unpublish({ publishDetails: entry, locale: "en-us", version: 1, scheduledAt: "2019-02-08T18:30:00.000Z"})
* .then((response) => console.log(response.notice))
*
*/
this.unpublish = unpublish(http, 'entry')
/**
* @description This multipurpose request allows you to either send a publish request or accept/reject a received publish request.
* @memberof Entry
* @func publishRequest
* @returns {Promise<Object>} Response Object.
* @param {Object} publishing_rule Details for the publish request
* @param {String} locale Enter the code of the locale that the entry belongs to.
* @example
* import * as contentstack from '@contentstack/management'
* const client = contentstack.client()
*
* const publishing_rule = {
* "uid": "uid",
* "action": "publish" //(‘publish’, ‘unpublish’, or ’both’)
* "status": 1, //(this could be ‘0’ for Approval Requested, ‘1’ for ‘Approval Accepted’, and ‘-1’ for ‘Approval Rejected’),
* "notify": false,
* comment": "Please review this."
* }
* client.stack({ api_key: 'api_key'}).contentType('content_type_uid').entry('uid').publishRequest({ publishing_rule, locale: 'en-us'})
* .then((response) => console.log(response.notice))
*/
this.publishRequest = async ({publishing_rule, locale}) => {
const publishDetails = {
workflow: { publishing_rule }
}
const headers = {}
if (this.stackHeaders) {
headers.headers = this.stackHeaders
}
headers.params = {
locale
}
try {
const response = await http.post(`${this.urlPath}/workflow`, publishDetails, headers)
if (response.data) {
return response.data
} else {
throw error(response)
}
} catch (err) {
throw error(err)
}
}
/**
* @description The Set Entry Workflow Stage request allows you to either set a particular workflow stage of an entry or update the workflow stage details of an entry.
* @memberof Entry
* @func setWorkflowStage
* @returns {Promise<Object>} Response Object.
* @param {Object} publishing_rule Details for the publish request
* @param {String} locale Enter the code of the locale that the entry belongs to.
* @example
* import * as contentstack from '@contentstack/management'
* const client = contentstack.client()
*
* const workflow_stage = {
* "comment": "Workflow Comment",
* "due_date": "Thu Dec 01 2018",
* "notify": false,
* "uid": "workflow_stage_uid",
* "assigned_to": [{
* "uid": "user_uid",
* "name": "Username",
* "email": "user_email_id"
* }],
* "assigned_by_roles": [{
* "uid": "role_uid",
* "name": "Role name"
* }]
* }
* client.stack({ api_key: 'api_key'}).contentType('content_type_uid').entry('uid').setWorkflowStage({ workflow_stage, locale: 'en-us'})
* .then((response) => console.log(response.notice));
*/
this.setWorkflowStage = async ({ workflow_stage, locale }) => {
const publishDetails = {
workflow: { workflow_stage }
}
const headers = {}
if (this.stackHeaders) {
headers.headers = this.stackHeaders
}
headers.params = {
locale
}
try {
const response = await http.post(`${this.urlPath}/workflow`, publishDetails, headers)
if (response.data) {
return response.data
} else {
throw error(response)
}
} catch (err) {
throw error(err)
}
}
} else {
/**
* @description The Create an entry call creates a new entry for the selected content type.
* @memberof Entry
* @func create
* @returns {Promise<Entry.Entry>} Promise for Entry instance
*
* @example
* import * as contentstack from '@contentstack/management'
* const client = contentstack.client()
* const entry = {
* title: 'Sample Entry',
* url: '/sampleEntry',
* file = asset_uid, // for single asset pass asset uid to entry asset field value
* multiple_file = ['asset_uid_1', 'asset_uid_2'], // for multiple asset pass array of asset uid to entry asset field values
* reference: reference.uid, // for single reference pass reference uid to entry reference field value
* multiple_reference: ['reference_uid_1', 'reference_uid_2'], // for multiple reference pass array of reference uid to entry reference field values
* multiple_content_type_reference: [{_content_type_uid: 'content_type_uid_1', uid: 'reference_uid_1'}, {_content_type_uid: 'content_type_uid_2', uid: 'reference_uid_2'}] // for multiple reference pass array of reference uid to entry reference field values
* }
* client.stack().contentType('content_type_uid').entry().create({ entry })
* .then((entry) => console.log(entry))
*/
this.create = create({ http: http })
/**
* @description The Query on Entry will allow to fetch details of all or specific Entry
* @memberof Entry
* @func query
* @param {Int} locale Enter the code of the language of which the entries need to be included. Only the entries published in this locale will be displayed.
* @param {Int} include_workflow Enter 'true' to include the workflow details of the entry.
* @param {Int} include_publish_details Enter 'true' to include the publish details of the entry.
* @param {Object} query Queries that you can use to fetch filtered results.
* @returns {Array<Entry>} Array of Entry.
*
* @example
* import * as contentstack from '@contentstack/management'
* const client = contentstack.client()
*
* client.stack().contentType('content_type_uid').entry().query({ query: { title: 'Entry title' } }).find()
* .then((entries) => console.log(entries))
*/
this.query = query({ http: http, wrapperCollection: EntryCollection })
}
/**
* @description The Import Entry calls given below help you to import entries by uploading JSON files.
* @memberof Entry
* @func import
* @param {String} entry Select the JSON file of the entry that you wish to import.
* @param {String} locale Enter the code of the language to import the entry of that particular language.
* @param {Boolean} overwrite Select 'true' to replace an existing entry with the imported entry file.
*
* @example
* import * as contentstack from '@contentstack/management'
* const client = contentstack.client()
*
* client.stack({ api_key: 'api_key'}).contentType('content_type_uid').entry()
* .import({
* entry: 'path/to/file.json',
* overwrite: true
* })
* .then((entry) => console.log(entry))
*
*/
this.import = async ({ entry, locale = null, overwrite = false }) => {
var importUrl = `${this.urlPath}/import?overwrite=${overwrite}`
if (locale) {
importUrl = `${importUrl}&locale=${locale}`
}
try {
const response = await upload({
http: http,
urlPath: importUrl,
stackHeaders: this.stackHeaders,
formData: createFormData(entry)
})
if (response.data) {
return new this.constructor(http, parseData(response, this.stackHeaders))
} else {
throw error(response)
}
} catch (err) {
throw error(err)
}
}
return this
}
export function EntryCollection (http, data) {
const obj = cloneDeep(data.entries) || []
const entryCollection = obj.map((entry) => {
return new Entry(http, { entry: entry, content_type_uid: data.content_type_uid, stackHeaders: data.stackHeaders })
})
return entryCollection
}
export function createFormData (entry) {
return () => {
const formData = new FormData()
const uploadStream = createReadStream(entry)
formData.append('entry', uploadStream)
return formData
}
}