Action

Post/Update to Micro.blog

Posted by donnydavis, Last update 7 days ago

UPDATES

7 days ago

  • Fixed a but with the authentication toke, where it was possible to include an empty space at the beginning or end. This would cause it to fail. Stripped out these spaces to avoid this issue.
  • Fixed an issue with cross posting. If you unchecked all options, it would cross post everywhere. Sorry about that. Now it should allow you to properly cross post how you choose.
  • New feature, Scheduled Posts. You can now schedule a post directly from Drafts. When creating the post just set the date and time that you would like the post to publish. At the moment you cannot change the scheduled date in Drafts, you will need to update that on the website for now.

Post to your Micro.blog hosted blog.

If you have multiple blogs, then you can select which one to post to. You can select if you would like to create a draft or publish directly. You can also select which, if any, categories to add.

If you would like a title for your post then add a # to the first line. Otherwise it will post without a title.

Posting options that are available:
* Setting the post status.
* Selecting cross posting targets.
* Selecting categories.

After posting, whether it’s a draft or published, you can use this action to update the post as well. To make this happen, there are tags added to the draft that contain the domain that it is posted to and the post slug. If these are removed then it will create a new post. There is also a tag added that reflects the post status, if it is a draft or published.

Steps

  • script

    // Post to Micro.blog Hosted Blog
    // 
    // Prompt for app token and set initial properties.
    
    var credential = Credential.create("Micro.blog", "Insert Micro.blog app token generated on Micro.blog account page.");
    credential.addPasswordField("apptoken", "App Token");
    
    credential.authorize();
    
    const appToken = credential.getValue("apptoken").toString().trim();
    const authorizationHeader = "Bearer " + appToken;
    const micropubEndpoint = "https://micro.blog/micropub";
    
    var currentDomain = "";
    if (draft.tags.some(item => item.startsWith("domain:"))) {
    	currentDomain = draft.tags
    		.find(item => item.startsWith("domain:"))
    		.replace("domain:", "");
    }
    
    var postURL = "";
    if (draft.tags.some(item => item.startsWith("post:"))) {
    	let postSlug = draft.tags
    		.find(item => item.startsWith("post:"))
    		.replace("post:", "");
    	postURL = currentDomain + postSlug;
    }
    let isUpdating = currentDomain.length > 1 && postURL.length > 1;
    
    var currentPostStatus = "";
    if (draft.tags.includes("draft")) {
    	currentPostStatus = "Draft";
    } else {
    	currentPostStatus = "Published";
    }
    
    var baseRequestObject = {
    	"url": "https://micro.blog/micropub",
    	"parameters": {},
    	"headers": {
    		"Authorization": authorizationHeader
    	},
    };
    
    var config = getConfigValues();
    
    function getConfigValues() {
    	let requestObject = baseRequestObject;
    	requestObject.method = "GET";
    	requestObject.parameters = {
    		"q": "config",
    	};
    
    	var req = HTTP.create();
    	var response = req.request(requestObject);
    
    	if (response.statusCode != 200 
    		&& response.statusCode != 202) {
    		console.log("Request for list of domains failed. Status code: " + response.statusCode);
    		context.fail();
    		
    	} else if (typeof(response.responseData.destination) == "undefined") {
    		console.log("Response for initial config info returned with no data.");
    		context.fail();
    		
    	} else {
    		var domainsArray = response.responseData.destination
    			.map(parseDomain);
    		
    		var syndicateToArray = response.responseData["syndicate-to"]
    			.map(target => target.uid.charAt(0).toUpperCase() + target.uid.slice(1));
    		
    		return {
    			"domains": domainsArray,
    			"syndicateTo": syndicateToArray
    		};
    	}
    }
    
    function parseDomain(domain) {
    	let host = domain.uid.split("://")[0];
    	return host + "://" + domain.name + "/";
    }
    
    
  • script

    // Post to Micro.blog Hosted Blog
    // 
    // Prompt for selected domain to post to.
    
    var selectedDomain = "";
    if (isUpdating) {
    	selectedDomain = currentDomain;
    } else {
    	promptForDomains();
    }
    
    // Prompt for a domain to post to
    function promptForDomains() {
    	var domains = config.domains;
    	var prompt = Prompt.create();
    	prompt.title = "Micro.blog Post";
    	prompt.message = "Select domain to post to.";
    
    	if (domains.length > 1) {
    		var defaultDomain = "";
    		if (isUpdating) {
    			defaultDomain = currentDomain;
    		} else {
    			defaultDomain = domains[0];
    		}
    		prompt.addSelect("domain", "Domains", domains, [defaultDomain], false);
    		
    	} else if (domains.length == 1) {
    		selectedDomain = domains[0];
    		return;
    		
    	} else {
    		console.log("No available domain to select from.");
    		context.fail();
    	}
    	
    	prompt.addButton("Next");
    	var promptResponse = prompt.show();
    	
    	if (promptResponse == false) {
    		console.log("Cancel button was pressed.");
    		context.fail();
    		
    	} else {
    		selectedDomain = prompt.fieldValues["domain"].toString();
    	}
    }
    
    
  • script

    // Post to Micro.blog Hosted Blog
    // 
    // Get a list of the categories for the selected domain
    
    let categories = getCategories();
    
    function getCategories() {
    	let requestObject = baseRequestObject;
    	requestObject.method = "GET";
    	requestObject.parameters = {
    		"q": "category",
    		"mp-destination": selectedDomain,
    	};
    
    	var req = HTTP.create();
    	var response = req.request(requestObject);
    	
    	console.log("Category Response: " + response.statusCode);
    	
    	if (response.statusCode != 200 
    		&& response.statusCode != 202) {
    		context.fail("Request for categories failed.");
    		
    	} else {
    		return response.responseData.categories;
    	}
    }
    
    
  • script

    // Post to Micro.blog Hosted Blog
    // 
    // Get any categories and published date for the post if previously published.
    
    var postProperties = {};
    if (postURL.trim().length != 0) {
    	postProperties = getPropertiesForPost();
    }
    
    function getPropertiesForPost() {
    	let requestObject = baseRequestObject;
    	requestObject.method = "GET";
    	requestObject.parameters = {
    		"q": "source",
    		"url": postURL,
    		"post-status": currentPostStatus.toLowerCase()
    	};
    	
    	var req = HTTP.create();
    	var response = req.request(requestObject);
    		
    	console.log("Category Response: " + response.statusCode);
    	
    	if (response.statusCode != 200 
    		&& response.statusCode != 202) {
    		context.fail("Request for selected categories failed.");
    		
    	} else {
    		var data = {
    			"selectedCategories": response.responseData.properties.category,
    		}
    		
    		if (response.responseData.properties.published) {
    			data.published = new Date(response.responseData.properties.published);
    		}
    		
    		return data;
    	}
    }
  • script

    // Post to Micro.blog Hosted Blog
    // 
    // Prompt for posting options.
    
    var postingOptions = {};
    
    promptForOptions();
    
    function promptForOptions() {	
    	var prompt = Prompt.create();
    	prompt.title = "Micro.blog Post";
    	prompt.message = "Select Posting Options";
    
    	if (draft.hasTag("published") == false) {
    		let postStatuses = [
    			"Published",
    			"Draft"
    		]
    		prompt.addSelect("postStatus", "Post Status", postStatuses, [currentPostStatus], false);
    		
    		if (isUpdating == false) {
    			var defaultPostDate = new Date();
    			if (postProperties.publishedDate) {
    				defaultPostDate = postProperties.publishedDate;
    			}
    			prompt.addDatePicker("publishDate", "Publish Date", defaultPostDate, {
    				"minimumDate": new Date(),
    				"mode": "dateAndTime"
    			});
    		}
    	}
    	
    	if (config.syndicateTo.length > 0 && isUpdating == false) {
    		prompt.addSelect("syndicateTo", "Cross Posting", config.syndicateTo, config.syndicateTo, true);
    	}
    		
    	if (categories.length > 0) {
    		prompt.addSelect("categories", "Categories", categories, postProperties.selectedCategories, true);
    	}
    		
    	if (isUpdating) {
    		prompt.addButton("Update");
    	} else {
    		prompt.addButton("Post");
    	}
    	var promptResponse = prompt.show();
    	
    	if (promptResponse == false) {
    		context.fail("User cancelled action");
    		
    	} else {
    		if (isUpdating) {
    			postingOptions = parseDataForUpdate(prompt);
    		} else {
    			postingOptions = parseDataForPost(prompt);
    		}
    	}
    }
    
    function parseDataForPost(prompt) {	
    	let postStatus = getPostStatus(prompt);
    	var data = {
    		"h": "entry",
    	 	"post-status": postStatus,
    	}
    
    	let syndicateToValues = prompt.fieldValues["syndicateTo"];
    	if (Array.isArray(syndicateToValues)) {
    		data["mp-syndicate-to"] = formatSyndicateToValues(syndicateToValues);
    	}
    	
    	if (hasTitle()) {
    	 	data.name = draft.processTemplate("[[safe_title]]");
    	 	data.content = draft.processTemplate("[[body]]");
    	} else {
    	 	data.content = draft.content;
    	}
    	
    	let categoryList = prompt.fieldValues["categories"];
    	if (categoryList) {
    		data.category = categoryList;
    	}
    	
    	let publishDate = prompt.fieldValues["publishDate"];
    	if (publishDate) {
    		data.published = publishDate;
    	}
    	
    	return data
    }
    
    function parseDataForUpdate(prompt) {
    	let postStatus = getPostStatus(prompt);
    	var data = {
    		"action": "update",
    		"url": postURL,
    	 	"replace": {
    	 		"post-status": [postStatus],
    	 	}
    	}
    	 		 
    	if (hasTitle()) {
    	 	data.replace.name = draft.processTemplate("[[safe_title]]");
    	 	data.replace.content = [draft.processTemplate("[[body]]")];
    	} else {
    	 	data.replace.content = [draft.content];
    	}
    	
    	let categoryList = prompt.fieldValues["categories"];
    	if (categoryList) {
    		data.replace.category = categoryList;
    	}
    		
    	return data
    }
    
    function hasTitle() {
    	let firstLine = draft.processTemplate("[[title]]");
    	return firstLine.startsWith("#");
    }
    
    function getPostStatus(prompt) {
    	if (prompt.fieldValues["postStatus"]) {
    		return prompt.fieldValues["postStatus"].toString().toLowerCase();
    	} else {
    		return currentPostStatus.toLowerCase();
    	}
    }
    
    function formatSyndicateToValues(syndicateTo) {
    	if (syndicateTo.length) {
    		return syndicateTo.map(element => element.toLowerCase());
    	} else {
    		return [""];
    	}
    }
    
    function isScheduled() {
    	if (postProperties.publishedDate) {
    		let currentDate = new Date().getTime();
    		let postDate = postProperties.publishedDate.getTime();
    		return postDate > currentDate;
    		
    	} else {
    		return false
    	}
    }
    
    
  • script

    // Post to Micro.blog Hosted Blog
    // 
    // Submit post
    
    let requestObject = baseRequestObject;
    requestObject.method = "POST";
    requestObject.parameters = {
    	"mp-destination": selectedDomain,
    };
    requestObject.data = postingOptions;
    if (isUpdating == false) {
    	requestObject.encoding = "form";
    }
    
    	
    let http = HTTP.create();
    let response = http.request(requestObject);
    
    if (response.statusCode != 200 
    	&& response.statusCode != 202) {
    	console.log("Post failed with status code: " + response.statusCode);
    	context.fail("Post failed.");
    
    } else {
    	setTags();
    }
    
    function setTags() {
    	if (isUpdating) {
    		draft.removeTag(currentPostStatus);
    		draft.addTag(postingOptions.replace["post-status"]);
    		let postTag = draft.tags
    			.find(item => item.startsWith("post:"));
    		draft.removeTag(postTag);
    			
    	} else {
    		draft.addTag(postingOptions["post-status"]);
    		draft.addTag("domain:" + selectedDomain);
    	}
    	let post = response.headers.Location
    				.replace(selectedDomain, "");
    	draft.addTag("post:" + post);
    	
    	draft.update();
    }
    
    

Options

  • After Success Default
    Notification Info
    Log Level Info
Items available in the Drafts Directory are uploaded by community members. Use appropriate caution reviewing downloaded items before use.