Skip to content

Instantly share code, notes, and snippets.

@on2air
Created February 26, 2020 21:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save on2air/de0a6d3f0b371d73564aba472f4cc01a to your computer and use it in GitHub Desktop.
Save on2air/de0a6d3f0b371d73564aba472f4cc01a to your computer and use it in GitHub Desktop.
This script enhanced the Content Calendar template with common functionality
/*****
 * Title: Enhanced Content Calendar
 * License: MIT
 * Author: Openside (Team behind On2Air products and BuiltOnAir community)
 * Sites:
 * https://openside.com - Openside Consulting Services
 * https://openside.com/#products - On2Air Products
 * https://builtonair.com - All things Airtable Community
 * 
 * Reach out for all your Airtable needs
 * 
 * Description: This script will enhance the Content Calendar Base by providing 2 common tasks:
 * 1) Create new Content - this easier approach to creating new content makes it quick to get content added to your table
 * 2) Publish Content - once you have created content, you want to publish it quickly to multiple platforms. This makes it easy
 * to track which platforms you are publishing it to (Twitter, Instagram, or Facebook) and automatically links it back to the primary content.
 * 
 * NOTE: This does not actually publish to Social media platforms, it simply tracks where you have published the content to and how.
 * 
* TEMPLATE: https://airtable.com/templates/featured/exp3FNmOkdHZvprXB/content-calendar
 * 
 * No changes are required to be made, simply run script and select one of the two options.
 * 
 */
//-----------------------------------
//Function: mkdLink
//Description: Create markdown for a link
//-----------------------------------
const mkdLink = (label, link) => {
    return `[${label}](${link})`
}
//-----------------------------------
//Function: getCollablId
//Description: looks up the collaborator id based on email
//-----------------------------------
const getCollabId = (email) => {
    email = email.trim().toLowerCase()
    let collabs = base.activeCollaborators
    for(let collab of collabs){
        if(collab.email.toLowerCase() === email){
            return collab.id
        }
    }
    return null
}
//-----------------------------------
//Function: cast
//Params: 
//table - The table model that is being updated (needed to get the field)
//field - The field name or id that will be updated
//value - the string value to be converted based on the field type
//Description: Converts a String value to the
//corresponding value needed to perform an update
//-----------------------------------
const cast = ( table, field, value ) => {
    let fieldMeta = table.getField(field)
    let type = fieldMeta.type
    return castType( type, value )
}
//-----------------------------------
//Function: castType
//Params: 
//type - the fieldType retrieved from table.getField(field).type
//value - the string value to be converted based on the field type
//Description: Converts a String value to the
//corresponding value needed to perform an update
//-----------------------------------
const castType = ( type, value ) => {
        
    if(type === 'singleSelect'){
        value = {name:value}
    
    }else if(type === 'multipleSelects'){
        let items = value.split(',')
        let values = []
        items.forEach( i => {
            values.push({name: i.trim()})
        })
        value = values
    
    }else if(type === 'number' || type === 'percent' || type === 'currency'){
        value = parseFloat(value)
    
    }else if(type === 'multipleRecordLinks'){
        let items = value.split(',')
        let values = []
        items.forEach( i => {
            values.push({id: i.trim()})
        })
        value = values
    
    }else if(type === 'singleRecordLink'){
        value = {id:value}
    
    }else if(type === 'multipleAttachments'){
        let items = value.split(',')
        let values = []
        items.forEach( i => {
            values.push({url: i.trim()})
        })
        value = values
    
    }else if(type === 'checkbox'){
        value = value === 1 || value === true || value === 'true' || value === '1' || value === 'yes' || value === 'on'
    
    }else if(type === 'barcode'){
        value = {text: value}
    
    }else if(type === 'rating' || type === 'duration'){
        value = parseInt(value)
    
    }else if(type === 'singleCollaborator'){
        value = {id: getCollabId(value)}
    
    }else if(type === 'multipleCollaborators'){
        let items = value.split(',')
        let values = []
        items.forEach( i => {
            values.push({id: getCollabId(i)})
        })
        value = values
    
    }else if(type === 'date' || type === 'dateTime'){
        value = value.trim().toLowerCase() === 'now' ? new Date().toISOString() : value
    
    }
    
    return value
}
let header = (msg = null) => {
    output.clear()
    output.markdown('# Content Tasks')
    if(msg){
        output.markdown(msg)
    }
    
}
const contentTable = base.tables[0]
const socialTable = base.tables[1]
const timesheetsTable = base.tables[2]
const optionsToButtons = async( label, field, selected = '', defualtVariant = 'secondary', optionValueKey = 'name', optionLabelKey = 'name' ) => {
    
    let options = field.options.choices
    let buttons = []
    for(let o=0; o<options.length; o++){
        let option = options[o]
        buttons.push({
            label: option[optionLabelKey],
            value: option[optionValueKey],
            variant: ( option.name === selected || option.id === selected ) ? 'primary' : defualtVariant
        })
    }
    return input.buttonsAsync(label, buttons )
}
const quickCreate = async( ) => {
    output.markdown('## Quick Create Content Calendar')
    output.markdown('Enter a blank space to leave any item blank')
    let headline = await input.textAsync('Enter the Headline')
    let subheadline = await input.textAsync('Enter the Sub-headline')
    let image = await input.textAsync('Enter the URL for the Header Image')
    let draft = await input.textAsync('Enter the Draft due date')
    let publish = await input.textAsync('Enter the Publish date')
    let link = await input.textAsync('Enter the Link to Content')
    let status = await optionsToButtons('Select the Status', contentTable.getField('Status'),'Planned')
    let section = await optionsToButtons('Select the Section', contentTable.getField('Section'),'')
    let author = await optionsToButtons('Select the Author', contentTable.getField('Author'),'', 'secondary', 'email')
    let data = {
        'Headline': headline.trim(),
        'Sub-headline': subheadline.trim(),
        'Header image': cast( contentTable, 'Header image', image),
        'Draft due': cast( contentTable, 'Draft due', draft),
        'Publish date': cast( contentTable, 'Publish date', publish),
        'Link': cast( contentTable, 'Link', link),
        'Status': cast( contentTable, 'Status', status),
        'Section': cast( contentTable, 'Section', section),
        'Author': cast( contentTable, 'Author', author)
    }
    console.log(data)
    let recId = await contentTable.createRecordAsync(data)
    
    let recLink = `https://airtable.com/${contentTable.id}/${recId}`
    return 'New Record Created. ' + mkdLink('Click Here to Review', recLink)
    
}
const publish = async( ) => {
    let selected = await input.recordAsync( 'Select Content to be published', contentTable, {
        shouldAllowCreatingRecord: false
    })
    let done = false
    
    let DONE_TEXT = 'DONE PUBLISHING'
    let published_to = []
    let selected_name = selected.getCellValueAsString('Headline')
    let selected_details = 
        selected.getCellValueAsString('Sub-headline')
        + "  \nAuthor: " + selected.getCellValueAsString('Author')
        + "  \nPublished: " + selected.getCellValueAsString('Publish date')
        + "  \nStatus: " + selected.getCellValueAsString('Status')
        + "  \nSection: " + selected.getCellValueAsString('Section')
    let details = {
        'Twitter': {length: 120},
        'Facebook': {length: 80},
        'Instagram': {length: 150}
    }
    while(!done){
        header('## ' + selected_name)
        output.markdown(selected_details)
        let platforms_text = ['Twitter','Instagram','Facebook',DONE_TEXT]
        let platforms = []
        for(let p=0;p<platforms_text.length;p++){
            let plat = platforms_text[p]
            platforms.push({
                label: plat,
                value: plat,
                variant: plat === DONE_TEXT ? 'secondary' : (published_to.includes(plat) ? 'danger' : 'default')
            })
        }
        let platform = await input.buttonsAsync('Select Platform to publish to',platforms)
        if(platform === DONE_TEXT){
            done = true
            //update original to set status
            await contentTable.updateRecordAsync( selected.id, {
                Status: {name: 'Published'}
            })
        }else{
            
            output.markdown('### ' + platform + ' Details')
            
            let post = await input.textAsync('Post (character limit: ' + details[platform]['length'] + ')')
            let date = await input.textAsync('Published Date (use \'now\' for today)')
            let link = await input.textAsync('Published Link')
            let doit = await input.buttonsAsync('Publish?', [{label:'PUBLISH',variant:'primary'},{label:'CANCEL',variant:'default'}])
            if(doit === 'PUBLISH'){
                published_to.push(platform)
                await socialTable.createRecordAsync({
                    'Social post': post,
                    'Platform': cast( socialTable,'Platform','Voyager ' + platform),
                    "Date": cast( socialTable, 'Date', date),
                    "Published link": cast(socialTable,'Published link',link),
                    "Related story": cast( socialTable,"Related story", selected.id)
                })
            }
        }
    }
    return published_to.length ? '##### Published to: ' + published_to.join(', ') : ''
}
let start = async(msg = null) => {
    header(msg)
    let selected = await input.buttonsAsync('Perform Task',[{
        label:'Quick Create',
        value: 'create',
    },{
        label:'Publish Content',
        value:'publish'
    }])
    let response = ''
    if(selected === 'create'){
        response = await quickCreate()
    }else if(selected === 'publish'){
        response = await publish()
    }
    await start(response)
}
await start()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment