Skip to content

Commit

Permalink
Fix: Preserve profilePositionGroups work ordering
Browse files Browse the repository at this point in the history
 - Closes #27
 - Version bump to v1.4.2
  • Loading branch information
joshuatz committed Aug 7, 2020
1 parent 55eee2a commit c6ca3ab
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 5 deletions.
12 changes: 12 additions & 0 deletions LinkedIn-Notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,17 @@ type PagingInfo = {
### Dash Endpoint(s)
As a quick side-note, I've noticed that a lot of the endpoints with `dash` anywhere in the path use the newer `decorationId` query syntax. This seems to also correspond with a shift in LI's UI towards true SPA functionality, where more of the page is lazy-loaded with filtered data that is slotted into Ember JS templates.
### Voyager Responses and Nested Data
Here are some quick notes on Voyager responses and how data is grouped / nested:
- *Elements* can be nested several layers deep; you might have an initial collection of elements, where each sub-element is actually a group that contains pointer to further collections of elements
- If you want to get the final layer of elements, you have to be careful about how you get them
- If you simply filter by `$type`, you are going to get elements out of order, and LI does not provide indexes (typically) on elements
- The only way to preserve the true order (which will match the rendered result on LI) is to traverse through levels
- Currently, `com.linkedin.restli.common.CollectionResponse` seems to be used for each layer where the element is a collection that points to sub elements (under `*elements`) key
- This can also make paging a little messy.
- LI has limits on certain endpoints, and the amount of nested elements it will return
- See [PR #23](https://github.com/joshuatz/linkedin-to-jsonresume/pull/23) for an example of how this was implemented
## LinkedIn TS Types
I've put some basics LI types in my `global.d.ts`. Eventually, it would be nice to re-write the core of this project as TS, as opposed to the current VSCode-powered typed JS approached.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ When in doubt, refresh the profile page before using this tool.
## Updates:
Date | Release | Notes
--- | --- | ---
7/7/2020 | 1.4.2 | Fix: For work positions, if fetched via `profilePositionGroups`, LI ordering (the way it looks on your profile) was not being preserved.
7/31/2020 | 1.4.1 | Fix: In some cases, wrong profileUrnId was extracted from current profile, which led to work history API call being ran against a *different* profile (e.g. from "recommended section", or something like that).
7/21/2020 | 1.4.0 | Fix: For vCard exports, Previous profile was getting grabbed after SPA navigation between profiles.
7/6/2020 | 1.3.0 | Fix: Incomplete work position entries for some users; LI was limiting the amount of pre-fetched data. Had to implement request paging to fix.<br/><br/>Also refactored a lot of code, improved result caching, and other tweaks.
Expand Down
4 changes: 4 additions & 0 deletions global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ interface InternalDb {
getValuesByKey: (key: LiUrn, optTocValModifier?: TocValModifier) => LiEntity[];
getElementsByType: (typeStr: string) => LiEntity[];
getElementByUrn: (urn: string) => LiEntity | undefined;
/**
* Get multiple elements by URNs
*/
getElementsByUrns: (urns: string[]) => LiEntity[];
}

interface LiProfileContactInfoResponse extends LiResponse {
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "linkedin-to-json-resume-exporter",
"version": "1.4.1",
"version": "1.4.2",
"description": "Browser tool to grab details from your open LinkedIn profile page and export to JSON Resume Schema",
"private": true,
"main": "src/main.js",
Expand Down
21 changes: 18 additions & 3 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ window.LinkedinToResumeJson = (() => {
db.getElementByUrn = function getElementByUrn(urn) {
return db.entitiesByUrn[urn];
};
db.getElementsByUrns = function getElementsByUrns(urns) {
return urns.map((urn) => db.entitiesByUrn[urn]);
};
db.getValueByKey = function getValueByKey(key) {
return db.entitiesByUrn[db.tableOfContents[key]];
};
Expand Down Expand Up @@ -1015,9 +1018,21 @@ window.LinkedinToResumeJson = (() => {
const db = buildDbFromLiSchema(response);
// profilePositionGroup responses are a little annoying; the direct children don't point directly to position entities
// Instead, you have to follow path of `profilePositionGroup` -> `*profilePositionInPositionGroup` -> `*elements` -> `Position`
// Faster to just bypass by looking up by `Position` type :)
db.getElementsByType('com.linkedin.voyager.dash.identity.profile.Position').forEach((position) => {
parseAndPushPosition(position);
// You can bypass by looking up by `Position` type, but then original ordering is not preserved
db.getElements().forEach((positionGroup) => {
// This element is how LI groups positions
// - E.g. promotions within same company are all grouped
// - Instead of storing *elements (positions) directly,
// there is a pointer to a "collection" that has to be followed
// - This multi-level traversal within the LI response could
// probably be refactored into a `db.*` method.
const collectionResponse = db.getElementByUrn(positionGroup['*profilePositionInPositionGroup']);
if (collectionResponse && Array.isArray(collectionResponse['*elements'])) {
db.getElementsByUrns(collectionResponse['*elements']).forEach((position) => {
// This is *finally* the "Position" element
parseAndPushPosition(position);
});
}
});
});
} catch (e) {
Expand Down

0 comments on commit c6ca3ab

Please sign in to comment.