-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bump dependencies to alleviate secruity issue, switch out github acti…
…on for creating env file to personally maintained one, update skills cron job to use node & proxycurl and run only once every 3 days.
- Loading branch information
Showing
12 changed files
with
224 additions
and
211 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
import { | ||
DeleteItemCommand, | ||
DynamoDBClient, | ||
PutItemCommand, | ||
QueryCommand, | ||
QueryCommandInput, | ||
UpdateItemCommand, | ||
} from "@aws-sdk/client-dynamodb"; | ||
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb"; | ||
import axios from "axios"; | ||
type SkillsType = { | ||
recordType: string; | ||
name: string; | ||
date_created: number | string; | ||
order: number | string; | ||
}; | ||
type DataFuncsParams = Pick<SkillsType, "order"> & { | ||
skillName: SkillsType["name"]; | ||
}; | ||
const tableName = process.env.AMAZON_DYNAMO_DB_TABLE_NAME; | ||
|
||
const client = new DynamoDBClient({ | ||
region: "us-east-1", | ||
}); | ||
const createSkill = async ({ skillName, order }: DataFuncsParams) => { | ||
const currentTimestamp = Date.now(); | ||
const item = { | ||
recordType: "skill", | ||
name: skillName, | ||
date_created: currentTimestamp.toString(), | ||
order, | ||
}; | ||
const putCommand = new PutItemCommand({ | ||
TableName: tableName, | ||
Item: marshall(item, { | ||
convertClassInstanceToMap: true, | ||
removeUndefinedValues: true, | ||
}), | ||
}); | ||
return await client.send(putCommand); | ||
}; | ||
const deleteSkill = async (skillName: string) => { | ||
const deleteCommand = new DeleteItemCommand({ | ||
TableName: tableName, | ||
Key: marshall( | ||
{ | ||
recordType: "skill", | ||
name: skillName, | ||
}, | ||
{ | ||
convertClassInstanceToMap: true, | ||
removeUndefinedValues: true, | ||
} | ||
), | ||
}); | ||
return await client.send(deleteCommand); | ||
}; | ||
const updateSkill = async ({ skillName, order }: DataFuncsParams) => { | ||
const updateCommand = new UpdateItemCommand({ | ||
TableName: tableName, | ||
Key: marshall( | ||
{ | ||
recordType: "skill", | ||
name: skillName, | ||
}, | ||
{ | ||
convertClassInstanceToMap: true, | ||
removeUndefinedValues: true, | ||
} | ||
), | ||
UpdateExpression: "SET #order = :order", | ||
ExpressionAttributeNames: { | ||
"#order": "order", | ||
}, | ||
ExpressionAttributeValues: marshall( | ||
{ | ||
":order": order, | ||
}, | ||
{ | ||
convertClassInstanceToMap: true, | ||
removeUndefinedValues: true, | ||
} | ||
), | ||
}); | ||
return await client.send(updateCommand); | ||
}; | ||
|
||
const getSkillsInDynamoDbTable = async () => { | ||
//create query command | ||
const expValMap = { | ||
":skill": "skill", | ||
}; | ||
const expVal = marshall(expValMap, { | ||
convertClassInstanceToMap: true, | ||
removeUndefinedValues: true, | ||
}); | ||
const query: QueryCommandInput = { | ||
TableName: tableName, | ||
KeyConditionExpression: "#rt = :skill", | ||
ExpressionAttributeNames: { | ||
"#rt": "recordType", | ||
}, | ||
ExpressionAttributeValues: expVal, | ||
}; | ||
//send command | ||
const command = new QueryCommand(query); | ||
const response = await client.send(command); | ||
const items = response.Items; | ||
if (!items) return []; | ||
const newItems = items.map((i) => unmarshall(i)) as SkillsType[]; | ||
return newItems; | ||
}; | ||
const getLinkedInSkills = async () => { | ||
try { | ||
const req = await axios({ | ||
method: "GET", | ||
url: `https://nubela.co/proxycurl/api/v2/linkedin`, | ||
headers: { | ||
Authorization: `Bearer ${process.env.PROXYCURL_TOKEN}`, | ||
}, | ||
params: { | ||
url: "https://linkedin.com/in/arky-asmal/", | ||
fallback_to_cache: "on-error", | ||
use_cache: "if-present", | ||
skills: "include", | ||
}, | ||
}); | ||
const data = req.data || {}; | ||
if (!data.skills) return []; | ||
const linkedInSkills = data.skills as string[]; | ||
return linkedInSkills; | ||
} catch (err) { | ||
return []; | ||
} | ||
}; | ||
const storeInDatabase = async (skills: string[]) => { | ||
const skillsInDB = await getSkillsInDynamoDbTable(); | ||
const skillsInDBMap: Record<string, SkillsType> = Object.assign( | ||
{}, | ||
...skillsInDB.map((val) => ({ [val.name]: val })) | ||
); | ||
const skillsInLinkedInMap: Record< | ||
string, | ||
Pick<SkillsType, "name" | "order"> | ||
> = Object.assign( | ||
{}, | ||
...skills.map((val, idx) => ({ | ||
[val]: { | ||
order: idx, | ||
name: val, | ||
}, | ||
})) | ||
); | ||
//loop through linkedin skills | ||
const modifyPromiseArr = skills.map((val, idx) => { | ||
//check if creation is needed | ||
const skillName = val; | ||
if (!(skillName in skillsInDBMap)) | ||
return createSkill({ | ||
skillName, | ||
order: idx, | ||
}); | ||
//check if update needed | ||
const storedIdx = skillsInDBMap[skillName].order; | ||
const parsedIdx = | ||
typeof storedIdx === "string" ? parseInt(storedIdx) : storedIdx; | ||
if (parsedIdx === idx) return null; | ||
return updateSkill({ | ||
skillName, | ||
order: idx, | ||
}); | ||
}); | ||
//check if deletion is needed | ||
//loop through skill in database already | ||
const deletePromiseArr = skillsInDB.map((val) => { | ||
const skillName = val.name; | ||
if (!(skillName in skillsInLinkedInMap)) return deleteSkill(skillName); | ||
return null; | ||
}); | ||
const results = await Promise.all([...modifyPromiseArr, ...deletePromiseArr]); | ||
return results; | ||
}; | ||
|
||
export async function handler() { | ||
const linkedInSkills = await getLinkedInSkills(); | ||
//this means failure, as LinkedIn skills will never be at zero | ||
if (linkedInSkills.length <= 0) return; | ||
const res = storeInDatabase(linkedInSkills); | ||
return res; | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.