Skip to content

Instantly share code, notes, and snippets.

@htammen
Last active February 16, 2021 22:32
Show Gist options
  • Save htammen/0b4ae0e7e747b1ac669b9b7f31f9d5a3 to your computer and use it in GitHub Desktop.
Save htammen/0b4ae0e7e747b1ac669b9b7f31f9d5a3 to your computer and use it in GitHub Desktop.
A script to get a list of (open) project offers
// This script reads open projects and outputs them to the console.
// This is quite messy cause I created it at a sunday evening.
// Will hopefully find time in the future to make it a bit more production ready
import {
decode as base64Decode,
encode as base64Encode,
} from 'https://deno.land/[email protected]/encoding/base64.ts';
import { ld } from 'https://x.nest.land/[email protected]/mod.ts'
import { parse } from "https://deno.land/std/flags/mod.ts"
import { format } from "https://deno.land/[email protected]/datetime/mod.ts";
/**
* returns a command line argument by name from the args array
*/
const getArg = function(argName: string, args: any[]): string {
//@ts-ignore
const arg = ld.find(args, (arg: string[]) => arg[0] === argName)
return arg ? arg[1]: null
}
/**
* check the status of Bitwarden. this script only works with bitwarden. It pulls
* the credentials for the server that is given at command line from the bitwarden
* password safe.
* @returns true if bitwarden is unlocked
*/
const checkBWStatus= async function(): Promise<boolean> {
const cmd = Deno.run({
cmd: ['bw', 'status'],
stdout: "piped",
stderr: "piped"
});
const output = await cmd.output() // "piped" must be set
const outStr = new TextDecoder('utf-8').decode(output);
// this is a hack cause TextDecoder returns a string beginning with 'Failed to decrypt' WHY??? We cut off this prefix
const str = outStr.substr(outStr.indexOf("{"))
log(str)
const status = JSON.parse(str)
cmd.close()
return status.status === "unlocked"
}
/**
* Helper method that logs a msg if debug flag is set
*/
const log=function(msg: any) {
if(bDebug) {
console.log(msg)
}
}
/**
* Returns the startDate to start the project search with.
* if commandline parameter fromdate is given it is used.
* if commandline parameter is not given the last 14 days will be used for search
*/
const getBeginDate = function(): string {
// check if start date is set. If not select projects for the last 14 days.
let startDateMillis = new Date().getTime()
if(startDateStr) {
startDateMillis = new Date(startDateStr).getTime()
} else {
let curDate = new Date()
// go 14 days back
const t=curDate.getTime()-(14*24*60*60*1000)
curDate.setTime(t)
startDateMillis = curDate.getTime()
}
return format(new Date(startDateMillis), "yyyy-MM-ddThh:mm:ss")
}
//console.log(parse(Deno.args))
// parse the args array into an array of 2-dimensionals array.
// Each array element is an array with 2 members: 0-argument, 1-argument value
const args = ld.toPairs(parse(Deno.args))
//console.log(args)
// save the command line parameters in variables.
const server = getArg('server', args)
const authurl = getArg('authurl', args)
const titleFilter = getArg('title', args)
const startDateStr = getArg('fromdate', args)
const bHelp = getArg('help', args)
const bDebug = getArg('debug', args)
log(args)
/** holds the status of bitwarden. true=unlocked */
const bwStatus = await checkBWStatus()
if(!bwStatus) {
console.error('Please login to Bitwarden to retrieve your server credentials')
Deno.exit(0)
}
// Show help screen if --help command line parameter was set
if(bHelp) {
console.log('PRJCRAWLER')
console.log('call this program with following options')
console.log(`
--server: name of the server to contact
--authurl: authentication url to use for retrieving the oAuth token
--title: search string used for querying projects
--fromdate: date to start the query with, default: last 14 days, format: 2020-12-24T00:00:00 (/w or w/o time part)
--help: show this help screen
--debug: output debug infos.
`)
Deno.exit(0);
}
const beginDateStr = getBeginDate()
// log the input data
console.log(`server: ${server}`)
console.log(`titleFilter: ${titleFilter}`)
console.log(`startDate: ${beginDateStr}`)
const getBitwardenField = async (fieldName:string, credEntry: string): Promise<string> => {
const cmd = Deno.run({
cmd: ['bw', 'get', fieldName, credEntry],
stdout: "piped",
stderr: "piped"
});
const output = await cmd.output() // "piped" must be set
const outStr = new TextDecoder().decode(output);
cmd.close()
return outStr
}
//console.log(server)
const username = await getBitwardenField('username', server)
const password = await getBitwardenField('password', server)
log(username)
const auth = base64Encode(`${username}:${password}`)
log(`base64encoded auth string: ${auth}`)
const authResponse = await fetch(authurl, {method: 'GET', headers: {'Authorization': 'Basic ' + auth}})
const authToken = await authResponse.text()
log(`authtoken: ${authToken}`)
let sFilter = `OriginalPublicationDate%20ge%20datetime'${beginDateStr}'`
if(titleFilter) {
sFilter += `%20and%20substringof(%27${titleFilter}%27,Title)`
}
log(sFilter)
const prjOffersUrl=`https://${server}/project-offer-backend/Data.svc/ProjectOffers?$skip=0&$top=30&$orderby=OriginalPublicationDate%20desc&$filter=${sFilter}`
log(prjOffersUrl)
const prjResult = await fetch(prjOffersUrl, {method: 'GET', headers: {'Authorization': 'Bearer ' + authToken, 'Accept': 'application/json'}})
log(prjResult)
const prjJSON = await prjResult.json()
if(bDebug) {
console.table(prjJSON.d.results, ["Title", "Location", "AgencyOrganization", "Url"])
}
const arrProjects:string[] = prjJSON.d.results.map((x:any) => {
return `${x.Title}\t>${x.Location}<\t>${x.AgencyOrganization}<\n${x.Url}\n---------------------------------------------------------------------------------------------------`
})
const arrPrefix = [
'------------------------------------------------------------------------------------------------------------------------',
'R E S U L T S',
'------------------------------------------------------------------------------------------------------------------------',
]
//@ts-ignore
const arrOutput = ld.concat(arrPrefix, arrProjects)
console.log(arrOutput.join('\n'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment