Skip to content

Commit

Permalink
Adds API key authentication support
Browse files Browse the repository at this point in the history
* also reworks FetchPost
* also includes notes in the post interface
  • Loading branch information
MarkSuckerberg committed Aug 3, 2023
1 parent d299140 commit 95f7361
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 12 deletions.
1 change: 1 addition & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,6 @@ jobs:
- run: npm run test:ci -- --coverage
env:
TUMBLR_TOKEN: ${{ steps.auth.outputs.tumblr-token }}
CONSUMER_ID: ${{ secrets.TUMBLR_CLIENT_ID }}
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
15 changes: 8 additions & 7 deletions src/functions/AccessTumblrApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { TumblrAPIResponse } from "../interfaces";

/**
* The function to access the Tumblr API. This function is used by the other functions in the project.
* @param token OAuth2 token from Tumblr
* @param token OAuth2 token from Tumblr (Or consumer ID if basicAuth is true)
* @param endpoint String of the endpoint to access
* @param params Additional query parameters to send to the API, will be sent as a JSON body if the method is not GET
* @param method HTTP method to use
* @param apiURL The API url to base the request off of
* @param basicAuth Whether or not to use the token as a basic API key rather than an OAuth2 token
* @returns JSON response from the Tumblr API
* @example accessTumblrAPI(tumblrToken, "blog/blogname.tumblr.com/posts", {limit: "1"}, "GET")
* @link https://www.tumblr.com/docs/en/api/v2
Expand All @@ -15,19 +17,18 @@ export async function accessTumblrAPI(
endpoint: string,
params?: Record<string, string>,
method: "GET" | "POST" | "DELETE" | "PUT" = "GET",
apiURL = "https://api.tumblr.com/v2/"
apiURL = "https://api.tumblr.com/v2/",
basicAuth = false
): Promise<TumblrAPIResponse> {
const url =
method === "GET"
? `${apiURL}${endpoint}?${new URLSearchParams(params)}`
: `${apiURL}${endpoint}`;
const finalParams = new URLSearchParams(basicAuth ? { api_key: token, ...params } : params);
const url = method === "GET" ? `${apiURL}${endpoint}?${finalParams}` : `${apiURL}${endpoint}`;
const request = await fetch(url, {
method: method,
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "Typeble/1.0.0",
"Authorization": `Bearer ${token}`,
...(!basicAuth && { Authorization: `Bearer ${token}` }),
},
body: method !== "GET" ? JSON.stringify(params) : null,
});
Expand Down
57 changes: 53 additions & 4 deletions src/functions/Post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export async function DeletePost(token: string, blogIdentifier: string, postId:
);
}

export async function FetchPost(
export async function FetchPostNeue(
token: string,
blogIdentifier: string,
postId: string,
Expand All @@ -80,6 +80,48 @@ export async function FetchPost(
).response;
}

/**
*
* @param token OAuth2 token from Tumblr
* @param blogIdentifier Identifier of the blog to fetch posts from
* @param id ID of the post to fetch
* @param reblogInfo Whether to include reblog info
* @param notesInfo Whether to include notes info
* @param filter Filter to apply to the posts (raw, text, none)
* @param npf Whether to use the new post format
* @param basicAuth Whether to treat the token argument as an OAuth2 token or a basic consumer ID
* @returns Specified post
* @link https://www.tumblr.com/docs/en/api/v2#posts--retrieve-published-posts
*/
export async function FetchPost<PostType extends TumblrPost = TumblrPost>(
token: string,
blogIdentifier: string,
id: number | string,
reblogInfo?: boolean,
notesInfo?: boolean,
filter: "raw" | "text" | "none" = "none",
npf = true,
basicAuth = false
) {
return (
await FetchPosts<PostType>(
token,
blogIdentifier,
id,
undefined,
1,
0,
reblogInfo,
notesInfo,
filter,
undefined,
npf,
undefined,
basicAuth
)
)[0];
}

/**
*
* @param token OAuth2 token from Tumblr
Expand All @@ -93,21 +135,25 @@ export async function FetchPost(
* @param filter Filter to apply to the posts (raw, text, none)
* @param before Unix timestamp to fetch posts before
* @param npf Whether to use the new post format
* @param type The type of posts to return, as legacy categories
* @param basicAuth Whether to treat the token argument as an OAuth2 token or a basic consumer ID
* @returns Array of posts
* @link https://www.tumblr.com/docs/en/api/v2#posts--retrieve-published-posts
*/
export async function FetchPosts<PostType extends TumblrPost = TumblrPost>(
token: string,
blogIdentifier: string,
id?: number,
id?: number | string,
tag?: string | string[],
limit = 20,
offset = 0,
reblogInfo?: boolean,
notesInfo?: boolean,
filter: "raw" | "text" | "none" = "none",
before?: number,
npf?: boolean
npf = true,
type?: "text" | "quote" | "link" | "answer" | "video" | "audio" | "photo" | "chat",
basicAuth = false
) {
// Tumblr API only allows a maximum of 20 posts per request
if (limit > 20) limit = 20;
Expand All @@ -122,6 +168,7 @@ export async function FetchPosts<PostType extends TumblrPost = TumblrPost>(
filter?: string;
before?: string;
npf?: string;
type?: string;
}

const args: Arguments = {
Expand All @@ -134,6 +181,7 @@ export async function FetchPosts<PostType extends TumblrPost = TumblrPost>(
filter: filter ?? "none",
before: before?.toString(),
npf: npf?.toString(),
type: type,
};

return (
Expand All @@ -143,7 +191,8 @@ export async function FetchPosts<PostType extends TumblrPost = TumblrPost>(
//TODO: This is a hacky way to do this. Find a better way to make this into a string array.
JSON.parse(JSON.stringify(args)),
"GET",
"https://www.tumblr.com/api/v2/" // Yes, getting posts needs to be done on a different API endpoint for some reason. Ask Tumblr why.
"https://www.tumblr.com/api/v2/", // Yes, getting posts needs to be done on a different API endpoint for some reason. Ask Tumblr why.
basicAuth
)
).response.posts as PostType[];
}
8 changes: 8 additions & 0 deletions src/interfaces/TumblrNeuePost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ export interface TumblrNeueLinkBlock {
export type TumblrNeueAudioBlock = TumblrNeueAudioBlockURL | TumblrNeueAudioBlockMedia;

export interface TumblrNeueAudioBlockBase {
url?: string;
media?: TumblrMediaObject;
type: "audio";
provider?: string;
title?: string;
Expand All @@ -98,16 +100,20 @@ export interface TumblrNeueAudioBlockBase {

export interface TumblrNeueAudioBlockURL extends TumblrNeueAudioBlockBase {
url: string;
media: never;
}

export interface TumblrNeueAudioBlockMedia extends TumblrNeueAudioBlockBase {
url: never;
media: TumblrMediaObject;
}

//Video Block
export type TumblrNeueVideoBlock = TumblrNeueVideoBlockURL | TumblrNeueVideoBlockMedia;

export interface TumblrNeueVideoBlockBase {
url?: string;
media?: TumblrMediaObject;
type: "video";
provider?: string;
embed_html?: string;
Expand All @@ -122,9 +128,11 @@ export interface TumblrNeueVideoBlockBase {
// Video Block
export interface TumblrNeueVideoBlockURL extends TumblrNeueVideoBlockBase {
url: string;
media: never;
}

export interface TumblrNeueVideoBlockMedia extends TumblrNeueVideoBlockBase {
url: never;
media: TumblrMediaObject;
}

Expand Down
15 changes: 15 additions & 0 deletions src/interfaces/TumblrPost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export interface TumblrPostBase {
can_send_in_message: boolean;
note_count: number;
should_open_in_legacy: boolean;
notes?: TumblrNote[];
}

export interface TumblrLegacyQueuedPost extends TumblrPostBase {
Expand Down Expand Up @@ -149,3 +150,17 @@ interface TumblrDialogue {
name: string;
phrase: string;
}

interface TumblrNote {
type: "like" | "reblog";
timestamp: number;
blog_name: string;
blog_uuid: string;
blog_url: string;
followed: boolean;
avatar_shape: string;
avatar_url: {
"64": string;
"128": string;
};
}
25 changes: 24 additions & 1 deletion tests/Posts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import {
DeletePost,
EditPost,
FetchPost,
FetchPostNeue,
FetchPosts,
NewPostDetails,
TumblrBlocksPost,
} from "../src";

const token = process.env.TUMBLR_TOKEN;
const consumerID = process.env.CONSUMER_ID;

if (!token) throw new Error("No token provided");
if (!consumerID) throw new Error("No consumer ID provided");

let postID: string | undefined;

Expand Down Expand Up @@ -43,7 +46,27 @@ it("should edit the post", async () => {

it("should fetch the post", async () => {
if (!postID) throw new Error("No post ID provided");
const post = (await FetchPost(token, "typeble-bot", postID)) as TumblrBlocksPost;
const post = (await FetchPostNeue(token, "typeble-bot", postID)) as TumblrBlocksPost;
expect(post.content).toEqual([
{ type: "text", text: "Hello, world!", subtype: "heading1" },
{ type: "text", text: "This is a test post. It has been edited!" },
]);
expect(post.tags).toEqual(["test", "typeble", "edit"]);
expect(post).toBeDefined();
});

it("should fetch the post with a consumer ID only", async () => {
if (!postID) throw new Error("No post ID provided");
const post = await FetchPost<TumblrBlocksPost>(
consumerID,
"typeble-bot",
postID,
undefined,
undefined,
undefined,
true,
true
);
expect(post.content).toEqual([
{ type: "text", text: "Hello, world!", subtype: "heading1" },
{ type: "text", text: "This is a test post. It has been edited!" },
Expand Down

0 comments on commit 95f7361

Please sign in to comment.