Skip to content

Instantly share code, notes, and snippets.

@royharmon4
Created March 26, 2023 18:53
Show Gist options
  • Select an option

  • Save royharmon4/fe93ed2b3a4d732d6662aa501b90c11d to your computer and use it in GitHub Desktop.

Select an option

Save royharmon4/fe93ed2b3a4d732d6662aa501b90c11d to your computer and use it in GitHub Desktop.
// Replace these with your own LinkedIn App's Client ID and Client Secret
const CLIENT_ID = '{INSERT CLIENT ID}';
const CLIENT_SECRET = '{INSERT CLIENT SECRET}';
// Replace this with your Google Sheet ID
const SPREADSHEET_ID = '{INSERT SPREADSHEET ID}';
// OAuth2 library
const LinkedInOAuth2 = OAuth2;
function getLinkedInService() {
return LinkedInOAuth2.createService('LinkedIn')
.setAuthorizationBaseUrl('https://www.linkedin.com/oauth/v2/authorization')
.setTokenUrl('https://www.linkedin.com/oauth/v2/accessToken')
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
.setCallbackFunction('authCallback')
.setPropertyStore(PropertiesService.getUserProperties())
.setScope('r_liteprofile w_member_social');
}
function showSidebar() {
const service = getLinkedInService();
if (!service.hasAccess()) {
const authorizationUrl = service.getAuthorizationUrl();
const template = HtmlService.createTemplate(`
<a href="<?= authorizationUrl ?>" target="_blank">Authorize</a>
<br>
<button onclick="window.top.close();">Close</button>
<script>
setTimeout(() => {
window.top.close();
}, 10000);
</script>
`);
template.authorizationUrl = authorizationUrl;
const page = template.evaluate();
SpreadsheetApp.getUi().showSidebar(page);
}
}
function authCallback(request) {
const service = getLinkedInService();
const authorized = service.handleCallback(request);
if (authorized) {
return HtmlService.createHtmlOutput('Success! You can close this tab.');
} else {
return HtmlService.createHtmlOutput('Failed to authenticate.');
}
}
function resetAuth() {
getLinkedInService().reset();
}
function schedulePosts() {
const service = getLinkedInService();
if (service.hasAccess()) {
const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getActiveSheet();
const data = sheet.getDataRange().getValues();
const header = data.shift();
const now = new Date();
data.forEach((row, index) => {
const rowData = row.reduce((obj, val, i) => {
obj[header[i]] = val;
return obj;
}, {});
const scheduledTime = rowData['Date and Time'];
if (scheduledTime instanceof Date && scheduledTime > now) {
const remainingMs = scheduledTime.getTime() - now.getTime();
ScriptApp.newTrigger('postToLinkedIn')
.timeBased()
.after(remainingMs)
.create();
}
});
} else {
showSidebar();
}
}
function postToLinkedIn() {
const service = getLinkedInService();
if (service.hasAccess()) {
const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getActiveSheet();
const data = sheet.getDataRange().getValues();
const header = data.shift();
const now = new Date();
data.forEach((row, index) => {
const rowData = row.reduce((obj, val, i) => {
obj[header[i]] = val;
return obj;
}, {});
const scheduledTime = rowData['Date and Time'];
if (scheduledTime instanceof Date && Math.abs(scheduledTime - now) < 60000) { // Check if the post is scheduled within 1 minute from now
const post = {
author: "urn:li:person:{INSERT LINKEDIN ID}",
lifecycleState: 'PUBLISHED',
specificContent: {
'com.linkedin.ugc.ShareContent': {
shareCommentary: {
text: rowData['Post Content']
},
shareMediaCategory: 'NONE'
}
},
visibility: {
'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC'
}
};
const options = {
method: 'POST',
contentType: 'application/json',
payload: JSON.stringify(post),
headers: {
Authorization: `Bearer ${service.getAccessToken()}`,
'X-Restli-Protocol-Version': '2.0.0'
}
};
const response = UrlFetchApp.fetch('https://api.linkedin.com/v2/ugcPosts', options);
const result = JSON.parse(response.getContentText());
if (response.getResponseCode() === 201) {
sheet.getRange(index + 2, header.indexOf('Status') + 1).setValue('Posted');
} else {
sheet.getRange(index + 2, header.indexOf('Status') + 1).setValue('Error');
}
}
});
} else {
showSidebar();
}
}
function onOpen() {
const ui = SpreadsheetApp.getUi();
ui.createMenu('LinkedIn')
.addItem('Schedule Posts', 'schedulePosts')
.addItem('Reset Authentication', 'resetAuth')
.addToUi();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment