From 50285bd049a8169a3bbcf74627d3d713af3ff385 Mon Sep 17 00:00:00 2001 From: Anon Date: Sun, 27 Nov 2022 21:25:00 -0600 Subject: [PATCH 1/6] Add custom emojis --- src/http.ts | 49 +++++++++++++++++++++++++++ src/interfaces/api/custom_emoji.ts | 54 ++++++++++++++++++++++++++++++ src/interfaces/api/index.ts | 1 + src/interfaces/api/site.ts | 2 ++ src/interfaces/others.ts | 3 ++ src/interfaces/source.ts | 20 +++++++++++ src/interfaces/views.ts | 9 +++++ src/websocket.ts | 26 ++++++++++++++ 8 files changed, 164 insertions(+) create mode 100644 src/interfaces/api/custom_emoji.ts diff --git a/src/http.ts b/src/http.ts index f93231f..1e1d870 100644 --- a/src/http.ts +++ b/src/http.ts @@ -34,6 +34,13 @@ import { RemoveCommunity, TransferCommunity, } from "./interfaces/api/community"; +import { + CreateCustomEmoji, + CustomEmojiResponse, + DeleteCustomEmoji, + DeleteCustomEmojiResponse, + EditCustomEmoji, +} from "./interfaces/api/custom_emoji"; import { AddAdmin, AddAdminResponse, @@ -1154,6 +1161,48 @@ export class LemmyHttp { ); } + /** + * Create a new custom emoji + * + * `HTTP.POST /custom_emoji` + */ + async createCustomEmoji(form: CreateCustomEmoji) { + return this.wrapper( + HttpType.Post, + "/custom_emoji", + form, + CustomEmojiResponse + ); + } + + /** + * Edit an existing custom emoji + * + * `HTTP.PUT /custom_emoji` + */ + async editCustomEmoji(form: EditCustomEmoji) { + return this.wrapper( + HttpType.Put, + "/custom_emoji", + form, + CustomEmojiResponse + ); + } + + /** + * Delete a custom emoji + * + * `HTTP.Post /custom_emoji/delete` + */ + async deleteCustomEmoji(form: DeleteCustomEmoji) { + return this.wrapper( + HttpType.Post, + "/custom_emoji/delete", + form, + DeleteCustomEmojiResponse + ); + } + private buildFullUrl(endpoint: string): string { return `${this.apiUrl}${endpoint}`; } diff --git a/src/interfaces/api/custom_emoji.ts b/src/interfaces/api/custom_emoji.ts new file mode 100644 index 0000000..47386b0 --- /dev/null +++ b/src/interfaces/api/custom_emoji.ts @@ -0,0 +1,54 @@ +import "reflect-metadata"; +import { CustomEmojiView } from "../views"; + +export class CreateCustomEmoji { + category: string; + shortcode: string; + image_url: string; + alt_text: string; + keywords: string[]; + auth: string; + + constructor(init: CreateCustomEmoji) { + Object.assign(this, init); + } +} + +export class EditCustomEmoji { + id: number; + category: string; + image_url: string; + alt_text: string; + keywords: string[]; + auth: string; + + constructor(init: EditCustomEmoji) { + Object.assign(this, init); + } +} + +export class DeleteCustomEmoji { + id: number; + auth: string; + + constructor(init: DeleteCustomEmoji) { + Object.assign(this, init); + } +} + +export class DeleteCustomEmojiResponse { + id: number; + success: boolean; + + constructor(init: DeleteCustomEmojiResponse) { + Object.assign(this, init); + } +} + +export class CustomEmojiResponse { + custom_emoji: CustomEmojiView; + + constructor(init: CustomEmojiResponse) { + Object.assign(this, init); + } +} diff --git a/src/interfaces/api/index.ts b/src/interfaces/api/index.ts index 81cff4d..e28cc3d 100644 --- a/src/interfaces/api/index.ts +++ b/src/interfaces/api/index.ts @@ -1,5 +1,6 @@ export * from "./comment"; export * from "./community"; +export * from "./custom_emoji"; export * from "./person"; export * from "./post"; export * from "./site"; diff --git a/src/interfaces/api/site.ts b/src/interfaces/api/site.ts index d8fd8bb..e5c59a9 100644 --- a/src/interfaces/api/site.ts +++ b/src/interfaces/api/site.ts @@ -10,6 +10,7 @@ import { CommunityFollowerView, CommunityModeratorView, CommunityView, + CustomEmojiView, LocalUserSettingsView, ModAddCommunityView, ModAddView, @@ -194,6 +195,7 @@ export interface GetSiteResponse { all_languages: Language[]; discussion_languages: number[]; taglines?: Tagline[]; + custom_emojis: CustomEmojiView[]; } /** diff --git a/src/interfaces/others.ts b/src/interfaces/others.ts index ea79e06..f1a306c 100644 --- a/src/interfaces/others.ts +++ b/src/interfaces/others.ts @@ -86,6 +86,9 @@ export enum UserOperation { GetReportCount, GetUnreadCount, VerifyEmail, + CreateCustomEmoji, + EditCustomEmoji, + DeleteCustomEmoji, } /** diff --git a/src/interfaces/source.ts b/src/interfaces/source.ts index eb278c2..110d8e6 100644 --- a/src/interfaces/source.ts +++ b/src/interfaces/source.ts @@ -386,3 +386,23 @@ export interface Tagline { published: string; updated?: string; } + +export class CustomEmoji { + id: number; + local_site_id: number; + shortcode: string; + image_url: string; + alt_text: string; + category: string; + published: string; + @Transform(({ value }) => toOption(value), { toClassOnly: true }) + @Transform(({ value }) => toUndefined(value), { toPlainOnly: true }) + @Expose() + updated: Option; +} + +export class CustomEmojiKeyword { + id: number; + custom_emoji_id: number; + keyword: string; +} diff --git a/src/interfaces/views.ts b/src/interfaces/views.ts index 40a95c9..18bce41 100644 --- a/src/interfaces/views.ts +++ b/src/interfaces/views.ts @@ -15,6 +15,8 @@ import { CommentReply, CommentReport, CommunitySafe, + CustomEmoji, + CustomEmojiKeyword, LocalSite, LocalSiteRateLimit, LocalUserSettings, @@ -289,3 +291,10 @@ export interface PrivateMessageReportView { creator: PersonSafe; resolver?: PersonSafe; } + +export class CustomEmojiView { + @Type(() => CustomEmoji) + custom_emoji: CustomEmoji; + @Type(() => CustomEmojiKeyword) + keywords: CustomEmojiKeyword[]; +} diff --git a/src/websocket.ts b/src/websocket.ts index 2afce29..2a6b933 100644 --- a/src/websocket.ts +++ b/src/websocket.ts @@ -23,6 +23,11 @@ import { RemoveCommunity, TransferCommunity, } from "./interfaces/api/community"; +import { + CreateCustomEmoji, + DeleteCustomEmoji, + EditCustomEmoji, +} from "./interfaces/api/custom_emoji"; import { AddAdmin, BanPerson, @@ -682,6 +687,27 @@ export class LemmyWebsocket { purgeComment(form: PurgeComment) { return wrapper(UserOperation.PurgeComment, form); } + + /** + * Create a custom emoji + */ + createCustomEmoji(form: CreateCustomEmoji) { + return wrapper(UserOperation.CreateCustomEmoji, form); + } + + /** + * Edit a custom emoji + */ + editCustomEmoji(form: EditCustomEmoji) { + return wrapper(UserOperation.EditCustomEmoji, form); + } + + /** + * Delete a custom emoji + */ + deleteCustomEmoji(form: DeleteCustomEmoji) { + return wrapper(UserOperation.DeleteCustomEmoji, form); + } } function wrapper(op: UserOperation, data: MessageType) { From 13ed39d527548995c14139b458ee31db362bd9fd Mon Sep 17 00:00:00 2001 From: Anon Date: Fri, 13 Jan 2023 17:51:10 -0600 Subject: [PATCH 2/6] Fixes for monads --- src/http.ts | 23 +++-------------------- src/interfaces/api/custom_emoji.ts | 1 - src/interfaces/api/site.ts | 2 +- src/interfaces/source.ts | 5 +---- src/interfaces/views.ts | 2 -- 5 files changed, 5 insertions(+), 28 deletions(-) diff --git a/src/http.ts b/src/http.ts index 1e1d870..47d4f94 100644 --- a/src/http.ts +++ b/src/http.ts @@ -36,9 +36,7 @@ import { } from "./interfaces/api/community"; import { CreateCustomEmoji, - CustomEmojiResponse, DeleteCustomEmoji, - DeleteCustomEmojiResponse, EditCustomEmoji, } from "./interfaces/api/custom_emoji"; import { @@ -1167,12 +1165,7 @@ export class LemmyHttp { * `HTTP.POST /custom_emoji` */ async createCustomEmoji(form: CreateCustomEmoji) { - return this.wrapper( - HttpType.Post, - "/custom_emoji", - form, - CustomEmojiResponse - ); + return this.wrapper(HttpType.Post, "/custom_emoji", form); } /** @@ -1181,12 +1174,7 @@ export class LemmyHttp { * `HTTP.PUT /custom_emoji` */ async editCustomEmoji(form: EditCustomEmoji) { - return this.wrapper( - HttpType.Put, - "/custom_emoji", - form, - CustomEmojiResponse - ); + return this.wrapper(HttpType.Put, "/custom_emoji", form); } /** @@ -1195,12 +1183,7 @@ export class LemmyHttp { * `HTTP.Post /custom_emoji/delete` */ async deleteCustomEmoji(form: DeleteCustomEmoji) { - return this.wrapper( - HttpType.Post, - "/custom_emoji/delete", - form, - DeleteCustomEmojiResponse - ); + return this.wrapper(HttpType.Post, "/custom_emoji/delete", form); } private buildFullUrl(endpoint: string): string { diff --git a/src/interfaces/api/custom_emoji.ts b/src/interfaces/api/custom_emoji.ts index 47386b0..df1bbef 100644 --- a/src/interfaces/api/custom_emoji.ts +++ b/src/interfaces/api/custom_emoji.ts @@ -1,4 +1,3 @@ -import "reflect-metadata"; import { CustomEmojiView } from "../views"; export class CreateCustomEmoji { diff --git a/src/interfaces/api/site.ts b/src/interfaces/api/site.ts index e5c59a9..7c2401d 100644 --- a/src/interfaces/api/site.ts +++ b/src/interfaces/api/site.ts @@ -194,7 +194,7 @@ export interface GetSiteResponse { federated_instances?: FederatedInstances; all_languages: Language[]; discussion_languages: number[]; - taglines?: Tagline[]; + taglines: Tagline[]; custom_emojis: CustomEmojiView[]; } diff --git a/src/interfaces/source.ts b/src/interfaces/source.ts index 110d8e6..1cc66be 100644 --- a/src/interfaces/source.ts +++ b/src/interfaces/source.ts @@ -395,10 +395,7 @@ export class CustomEmoji { alt_text: string; category: string; published: string; - @Transform(({ value }) => toOption(value), { toClassOnly: true }) - @Transform(({ value }) => toUndefined(value), { toPlainOnly: true }) - @Expose() - updated: Option; + updated: string; } export class CustomEmojiKeyword { diff --git a/src/interfaces/views.ts b/src/interfaces/views.ts index 18bce41..b1caddf 100644 --- a/src/interfaces/views.ts +++ b/src/interfaces/views.ts @@ -293,8 +293,6 @@ export interface PrivateMessageReportView { } export class CustomEmojiView { - @Type(() => CustomEmoji) custom_emoji: CustomEmoji; - @Type(() => CustomEmojiKeyword) keywords: CustomEmojiKeyword[]; } From c13af053f0decd892d7c24b83761a126efc73b9a Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 2 Mar 2023 18:26:44 -0500 Subject: [PATCH 3/6] Totp (#106) * Adding TOTP support. * v0.17.2-rc.2 * Fix name. * v0.17.2-rc.3 --- package.json | 2 +- src/interfaces/api/person.ts | 13 +++++++++++++ src/interfaces/source.ts | 4 ++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index f572c33..c1fd321 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lemmy-js-client", - "version": "0.17.2-rc.1", + "version": "0.17.2-rc.3", "description": "A javascript / typescript client for Lemmy", "repository": "https://github.com/LemmyNet/lemmy-js-client", "license": "AGPL-3.0", diff --git a/src/interfaces/api/person.ts b/src/interfaces/api/person.ts index 81dfc69..7210955 100644 --- a/src/interfaces/api/person.ts +++ b/src/interfaces/api/person.ts @@ -13,6 +13,10 @@ import { export interface Login { username_or_email: string; password: string; + /** + * If your user has 2fa set up, they must provide the token, otherwise you will receive the error "missing_totp_token" + */ + totp_2fa_token?: string; } /** @@ -103,6 +107,15 @@ export interface SaveUserSettings { show_read_posts?: boolean; show_new_post_notifs?: boolean; discussion_languages?: number[]; + /** + * If this is set to true, lemmy will generate or regenerate a 2-factor (totp) authentication secret. + * You can then use the `totp_2fa_url` from [[LocalUserSettings]] to set up your authenticator app. + * + * If this is set to false, it will remove 2-factor for your account. + * + * If this is undefined, it leaves your 2-factor setup as is. + */ + generate_totp_2fa?: boolean; auth: string; } diff --git a/src/interfaces/source.ts b/src/interfaces/source.ts index 404b348..97a1ba4 100644 --- a/src/interfaces/source.ts +++ b/src/interfaces/source.ts @@ -16,6 +16,10 @@ export interface LocalUserSettings { show_new_post_notifs: boolean; email_verified: boolean; accepted_application: boolean; + /** + * An installation url for your 2-factor authenticator app. + */ + totp_2fa_url?: string; } export interface PersonSafe { From 077c9782b126e2510e361551ff76f98322663dce Mon Sep 17 00:00:00 2001 From: SleeplessOne1917 Date: Fri, 17 Mar 2023 11:33:57 -0400 Subject: [PATCH 4/6] docs: Fix incorrect code sample in README (#109) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c53ce12..942aebc 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ import { LemmyHttp } from 'lemmy-js-client'; let baseUrl = 'https://lemmy.ml'; let client: LemmyHttp = new LemmyHttp(baseUrl, headers?); -let jwt = await client.httpLogin(loginForm).jwt; +let jwt = await client.login(loginForm).jwt; ``` ## Development From de4414b877b3f1f48c992aab0c1048d17bbea2a4 Mon Sep 17 00:00:00 2001 From: SleeplessOne1917 Date: Wed, 22 Mar 2023 14:33:54 -0400 Subject: [PATCH 5/6] feat: add image upload method to http client (#108) * feat: add image upload method to http client * fix: Make files optional on UploadImageResponse * fix: Fix comment typo * fix: replace loose equals with strict equals * fix: Remove useless awaits * fix: Add explicit return types to image upload helper functions * fix: Include client headers in image upload request * fix: Change type of uploadImage arg to File | Buffer instead of Blob | Buffer * doc: Add doc string * refactor: Switch to using cross-fetch instead of node-fetch v3 * chore: remove unnecessary asyncs --- package.json | 4 +- src/http.ts | 244 +++++++++++++++++++++++++-------------- src/interfaces/others.ts | 23 ++++ tsconfig.json | 7 +- yarn.lock | 31 +++-- 5 files changed, 198 insertions(+), 111 deletions(-) diff --git a/package.json b/package.json index c1fd321..897e124 100644 --- a/package.json +++ b/package.json @@ -26,11 +26,11 @@ ] }, "dependencies": { - "node-fetch": "2.6.6" + "cross-fetch": "^3.1.5", + "form-data": "^4.0.0" }, "devDependencies": { "@types/node": "^18.6.2", - "@types/node-fetch": "2.6.2", "@typescript-eslint/eslint-plugin": "^5.31.0", "@typescript-eslint/parser": "^5.31.0", "eslint": "^8.20.0", diff --git a/src/http.ts b/src/http.ts index 47d4f94..1eb01f7 100644 --- a/src/http.ts +++ b/src/http.ts @@ -1,4 +1,6 @@ -import fetch from "node-fetch"; +import fetch from "cross-fetch"; +import FormData from "form-data"; + import { CommentReportResponse, CommentResponse, @@ -136,7 +138,7 @@ import { SearchResponse, SiteResponse, } from "./interfaces/api/site"; -import { VERSION } from "./interfaces/others"; +import { UploadImage, UploadImageResponse, VERSION } from "./interfaces/others"; enum HttpType { Get = "GET", @@ -150,6 +152,7 @@ enum HttpType { export class LemmyHttp { private apiUrl: string; private headers: { [key: string]: string } = {}; + private pictrsUrl: string; /** * Generates a new instance of LemmyHttp. @@ -158,6 +161,7 @@ export class LemmyHttp { */ constructor(baseUrl: string, headers?: { [key: string]: string }) { this.apiUrl = `${baseUrl}/api/${VERSION}`; + this.pictrsUrl = `${baseUrl}/pictrs/image`; if (headers) { this.headers = headers; @@ -169,7 +173,7 @@ export class LemmyHttp { * * `HTTP.GET /site` */ - async getSite(form: GetSite) { + getSite(form: GetSite) { return this.wrapper(HttpType.Get, "/site", form); } @@ -178,7 +182,7 @@ export class LemmyHttp { * * `HTTP.POST /site` */ - async createSite(form: CreateSite) { + createSite(form: CreateSite) { return this.wrapper(HttpType.Post, "/site", form); } @@ -187,7 +191,7 @@ export class LemmyHttp { * * `HTTP.PUT /site` */ - async editSite(form: EditSite) { + editSite(form: EditSite) { return this.wrapper(HttpType.Put, "/site", form); } @@ -196,7 +200,7 @@ export class LemmyHttp { * * `HTTP.POST /user/leave_admin` */ - async leaveAdmin(form: LeaveAdmin) { + leaveAdmin(form: LeaveAdmin) { return this.wrapper( HttpType.Post, "/user/leave_admin", @@ -209,7 +213,7 @@ export class LemmyHttp { * * `HTTP.GET /modlog` */ - async getModlog(form: GetModlog) { + getModlog(form: GetModlog) { return this.wrapper( HttpType.Get, "/modlog", @@ -222,7 +226,7 @@ export class LemmyHttp { * * `HTTP.GET /search` */ - async search(form: Search) { + search(form: Search) { return this.wrapper(HttpType.Get, "/search", form); } @@ -231,7 +235,7 @@ export class LemmyHttp { * * `HTTP.GET /resolve_object` */ - async resolveObject(form: ResolveObject) { + resolveObject(form: ResolveObject) { return this.wrapper( HttpType.Get, "/resolve_object", @@ -244,7 +248,7 @@ export class LemmyHttp { * * `HTTP.POST /community` */ - async createCommunity(form: CreateCommunity) { + createCommunity(form: CreateCommunity) { return this.wrapper( HttpType.Post, "/community", @@ -257,7 +261,7 @@ export class LemmyHttp { * * `HTTP.GET /community` */ - async getCommunity(form: GetCommunity) { + getCommunity(form: GetCommunity) { return this.wrapper( HttpType.Get, "/community", @@ -270,7 +274,7 @@ export class LemmyHttp { * * `HTTP.PUT /community` */ - async editCommunity(form: EditCommunity) { + editCommunity(form: EditCommunity) { return this.wrapper( HttpType.Put, "/community", @@ -283,7 +287,7 @@ export class LemmyHttp { * * `HTTP.GET /community/list` */ - async listCommunities(form: ListCommunities) { + listCommunities(form: ListCommunities) { return this.wrapper( HttpType.Get, "/community/list", @@ -296,7 +300,7 @@ export class LemmyHttp { * * `HTTP.POST /community/follow` */ - async followCommunity(form: FollowCommunity) { + followCommunity(form: FollowCommunity) { return this.wrapper( HttpType.Post, "/community/follow", @@ -309,7 +313,7 @@ export class LemmyHttp { * * `HTTP.POST /community/block` */ - async blockCommunity(form: BlockCommunity) { + blockCommunity(form: BlockCommunity) { return this.wrapper( HttpType.Post, "/community/block", @@ -322,7 +326,7 @@ export class LemmyHttp { * * `HTTP.POST /community/delete` */ - async deleteCommunity(form: DeleteCommunity) { + deleteCommunity(form: DeleteCommunity) { return this.wrapper( HttpType.Post, "/community/delete", @@ -335,7 +339,7 @@ export class LemmyHttp { * * `HTTP.POST /community/remove` */ - async removeCommunity(form: RemoveCommunity) { + removeCommunity(form: RemoveCommunity) { return this.wrapper( HttpType.Post, "/community/remove", @@ -348,7 +352,7 @@ export class LemmyHttp { * * `HTTP.POST /community/transfer` */ - async transferCommunity(form: TransferCommunity) { + transferCommunity(form: TransferCommunity) { return this.wrapper( HttpType.Post, "/community/transfer", @@ -361,7 +365,7 @@ export class LemmyHttp { * * `HTTP.POST /community/ban_user` */ - async banFromCommunity(form: BanFromCommunity) { + banFromCommunity(form: BanFromCommunity) { return this.wrapper( HttpType.Post, "/community/ban_user", @@ -374,7 +378,7 @@ export class LemmyHttp { * * `HTTP.POST /community/mod` */ - async addModToCommunity(form: AddModToCommunity) { + addModToCommunity(form: AddModToCommunity) { return this.wrapper( HttpType.Post, "/community/mod", @@ -387,7 +391,7 @@ export class LemmyHttp { * * `HTTP.POST /post` */ - async createPost(form: CreatePost) { + createPost(form: CreatePost) { return this.wrapper(HttpType.Post, "/post", form); } @@ -396,7 +400,7 @@ export class LemmyHttp { * * `HTTP.GET /post` */ - async getPost(form: GetPost) { + getPost(form: GetPost) { return this.wrapper(HttpType.Get, "/post", form); } @@ -405,7 +409,7 @@ export class LemmyHttp { * * `HTTP.PUT /post` */ - async editPost(form: EditPost) { + editPost(form: EditPost) { return this.wrapper(HttpType.Put, "/post", form); } @@ -414,7 +418,7 @@ export class LemmyHttp { * * `HTTP.POST /post/delete` */ - async deletePost(form: DeletePost) { + deletePost(form: DeletePost) { return this.wrapper( HttpType.Post, "/post/delete", @@ -427,7 +431,7 @@ export class LemmyHttp { * * `HTTP.POST /post/remove` */ - async removePost(form: RemovePost) { + removePost(form: RemovePost) { return this.wrapper( HttpType.Post, "/post/remove", @@ -440,7 +444,7 @@ export class LemmyHttp { * * `HTTP.POST /post/mark_as_read` */ - async markPostAsRead(form: MarkPostAsRead) { + markPostAsRead(form: MarkPostAsRead) { return this.wrapper( HttpType.Post, "/post/mark_as_read", @@ -453,7 +457,7 @@ export class LemmyHttp { * * `HTTP.POST /post/lock` */ - async lockPost(form: LockPost) { + lockPost(form: LockPost) { return this.wrapper( HttpType.Post, "/post/lock", @@ -466,7 +470,7 @@ export class LemmyHttp { * * `HTTP.POST /post/feature` */ - async featurePost(form: FeaturePost) { + featurePost(form: FeaturePost) { return this.wrapper( HttpType.Post, "/post/feature", @@ -479,7 +483,7 @@ export class LemmyHttp { * * `HTTP.GET /post/list` */ - async getPosts(form: GetPosts) { + getPosts(form: GetPosts) { return this.wrapper( HttpType.Get, "/post/list", @@ -492,7 +496,7 @@ export class LemmyHttp { * * `HTTP.POST /post/like` */ - async likePost(form: CreatePostLike) { + likePost(form: CreatePostLike) { return this.wrapper( HttpType.Post, "/post/like", @@ -505,7 +509,7 @@ export class LemmyHttp { * * `HTTP.PUT /post/save` */ - async savePost(form: SavePost) { + savePost(form: SavePost) { return this.wrapper( HttpType.Put, "/post/save", @@ -518,7 +522,7 @@ export class LemmyHttp { * * `HTTP.POST /post/report` */ - async createPostReport(form: CreatePostReport) { + createPostReport(form: CreatePostReport) { return this.wrapper( HttpType.Post, "/post/report", @@ -531,7 +535,7 @@ export class LemmyHttp { * * `HTTP.PUT /post/report/resolve` */ - async resolvePostReport(form: ResolvePostReport) { + resolvePostReport(form: ResolvePostReport) { return this.wrapper( HttpType.Put, "/post/report/resolve", @@ -544,7 +548,7 @@ export class LemmyHttp { * * `HTTP.GET /post/report/list` */ - async listPostReports(form: ListPostReports) { + listPostReports(form: ListPostReports) { return this.wrapper( HttpType.Get, "/post/report/list", @@ -557,7 +561,7 @@ export class LemmyHttp { * * `HTTP.GET /post/site_metadata` */ - async getSiteMetadata(form: GetSiteMetadata) { + getSiteMetadata(form: GetSiteMetadata) { return this.wrapper( HttpType.Get, "/post/site_metadata", @@ -570,7 +574,7 @@ export class LemmyHttp { * * `HTTP.POST /comment` */ - async createComment(form: CreateComment) { + createComment(form: CreateComment) { return this.wrapper( HttpType.Post, "/comment", @@ -583,7 +587,7 @@ export class LemmyHttp { * * `HTTP.PUT /comment` */ - async editComment(form: EditComment) { + editComment(form: EditComment) { return this.wrapper( HttpType.Put, "/comment", @@ -596,7 +600,7 @@ export class LemmyHttp { * * `HTTP.POST /comment/delete` */ - async deleteComment(form: DeleteComment) { + deleteComment(form: DeleteComment) { return this.wrapper( HttpType.Post, "/comment/delete", @@ -609,7 +613,7 @@ export class LemmyHttp { * * `HTTP.POST /comment/remove` */ - async removeComment(form: RemoveComment) { + removeComment(form: RemoveComment) { return this.wrapper( HttpType.Post, "/comment/remove", @@ -622,7 +626,7 @@ export class LemmyHttp { * * `HTTP.POST /comment/mark_as_read` */ - async markCommentReplyAsRead(form: MarkCommentReplyAsRead) { + markCommentReplyAsRead(form: MarkCommentReplyAsRead) { return this.wrapper( HttpType.Post, "/comment/mark_as_read", @@ -635,7 +639,7 @@ export class LemmyHttp { * * `HTTP.POST /comment/like` */ - async likeComment(form: CreateCommentLike) { + likeComment(form: CreateCommentLike) { return this.wrapper( HttpType.Post, "/comment/like", @@ -648,7 +652,7 @@ export class LemmyHttp { * * `HTTP.PUT /comment/save` */ - async saveComment(form: SaveComment) { + saveComment(form: SaveComment) { return this.wrapper( HttpType.Put, "/comment/save", @@ -661,7 +665,7 @@ export class LemmyHttp { * * `HTTP.GET /comment/list` */ - async getComments(form: GetComments) { + getComments(form: GetComments) { return this.wrapper( HttpType.Get, "/comment/list", @@ -674,7 +678,7 @@ export class LemmyHttp { * * `HTTP.POST /comment/report` */ - async createCommentReport(form: CreateCommentReport) { + createCommentReport(form: CreateCommentReport) { return this.wrapper( HttpType.Post, "/comment/report", @@ -687,7 +691,7 @@ export class LemmyHttp { * * `HTTP.PUT /comment/report/resolve` */ - async resolveCommentReport(form: ResolveCommentReport) { + resolveCommentReport(form: ResolveCommentReport) { return this.wrapper( HttpType.Put, "/comment/report/resolve", @@ -700,7 +704,7 @@ export class LemmyHttp { * * `HTTP.GET /comment/report/list` */ - async listCommentReports(form: ListCommentReports) { + listCommentReports(form: ListCommentReports) { return this.wrapper( HttpType.Get, "/comment/report/list", @@ -713,7 +717,7 @@ export class LemmyHttp { * * `HTTP.GET /private_message/list` */ - async getPrivateMessages(form: GetPrivateMessages) { + getPrivateMessages(form: GetPrivateMessages) { return this.wrapper( HttpType.Get, "/private_message/list", @@ -726,7 +730,7 @@ export class LemmyHttp { * * `HTTP.POST /private_message` */ - async createPrivateMessage(form: CreatePrivateMessage) { + createPrivateMessage(form: CreatePrivateMessage) { return this.wrapper( HttpType.Post, "/private_message", @@ -739,7 +743,7 @@ export class LemmyHttp { * * `HTTP.PUT /private_message` */ - async editPrivateMessage(form: EditPrivateMessage) { + editPrivateMessage(form: EditPrivateMessage) { return this.wrapper( HttpType.Put, "/private_message", @@ -752,7 +756,7 @@ export class LemmyHttp { * * `HTTP.POST /private_message/delete` */ - async deletePrivateMessage(form: DeletePrivateMessage) { + deletePrivateMessage(form: DeletePrivateMessage) { return this.wrapper( HttpType.Post, "/private_message/delete", @@ -765,7 +769,7 @@ export class LemmyHttp { * * `HTTP.POST /private_message/mark_as_read` */ - async markPrivateMessageAsRead(form: MarkPrivateMessageAsRead) { + markPrivateMessageAsRead(form: MarkPrivateMessageAsRead) { return this.wrapper( HttpType.Post, "/private_message/mark_as_read", @@ -778,7 +782,7 @@ export class LemmyHttp { * * `HTTP.POST /private_message/report` */ - async createPrivateMessageReport(form: CreatePrivateMessageReport) { + createPrivateMessageReport(form: CreatePrivateMessageReport) { return this.wrapper< CreatePrivateMessageReport, PrivateMessageReportResponse @@ -790,7 +794,7 @@ export class LemmyHttp { * * `HTTP.PUT /private_message/report/resolve` */ - async resolvePrivateMessageReport(form: ResolvePrivateMessageReport) { + resolvePrivateMessageReport(form: ResolvePrivateMessageReport) { return this.wrapper< ResolvePrivateMessageReport, PrivateMessageReportResponse @@ -802,7 +806,7 @@ export class LemmyHttp { * * `HTTP.GET /private_message/report/list` */ - async listPrivateMessageReports(form: ListPrivateMessageReports) { + listPrivateMessageReports(form: ListPrivateMessageReports) { return this.wrapper< ListPrivateMessageReports, ListPrivateMessageReportsResponse @@ -814,7 +818,7 @@ export class LemmyHttp { * * `HTTP.POST /user/register` */ - async register(form: Register) { + register(form: Register) { return this.wrapper( HttpType.Post, "/user/register", @@ -827,7 +831,7 @@ export class LemmyHttp { * * `HTTP.POST /user/login` */ - async login(form: Login) { + login(form: Login) { return this.wrapper( HttpType.Post, "/user/login", @@ -840,7 +844,7 @@ export class LemmyHttp { * * `HTTP.GET /user` */ - async getPersonDetails(form: GetPersonDetails) { + getPersonDetails(form: GetPersonDetails) { return this.wrapper( HttpType.Get, "/user", @@ -853,7 +857,7 @@ export class LemmyHttp { * * `HTTP.GET /user/mention` */ - async getPersonMentions(form: GetPersonMentions) { + getPersonMentions(form: GetPersonMentions) { return this.wrapper( HttpType.Get, "/user/mention", @@ -866,7 +870,7 @@ export class LemmyHttp { * * `HTTP.POST /user/mention/mark_as_read` */ - async markPersonMentionAsRead(form: MarkPersonMentionAsRead) { + markPersonMentionAsRead(form: MarkPersonMentionAsRead) { return this.wrapper( HttpType.Post, "/user/mention/mark_as_read", @@ -879,7 +883,7 @@ export class LemmyHttp { * * `HTTP.GET /user/replies` */ - async getReplies(form: GetReplies) { + getReplies(form: GetReplies) { return this.wrapper( HttpType.Get, "/user/replies", @@ -892,7 +896,7 @@ export class LemmyHttp { * * `HTTP.POST /user/ban` */ - async banPerson(form: BanPerson) { + banPerson(form: BanPerson) { return this.wrapper( HttpType.Post, "/user/ban", @@ -905,7 +909,7 @@ export class LemmyHttp { * * `HTTP.GET /user/banned` */ - async getBannedPersons(form: GetBannedPersons) { + getBannedPersons(form: GetBannedPersons) { return this.wrapper( HttpType.Get, "/user/banned", @@ -918,7 +922,7 @@ export class LemmyHttp { * * `HTTP.POST /user/block` */ - async blockPerson(form: BlockPerson) { + blockPerson(form: BlockPerson) { return this.wrapper( HttpType.Post, "/user/block", @@ -931,7 +935,7 @@ export class LemmyHttp { * * `HTTP.GET /user/get_captcha` */ - async getCaptcha() { + getCaptcha() { return this.wrapper( HttpType.Get, "/user/get_captcha", @@ -944,7 +948,7 @@ export class LemmyHttp { * * `HTTP.POST /user/delete_account` */ - async deleteAccount(form: DeleteAccount) { + deleteAccount(form: DeleteAccount) { return this.wrapper( HttpType.Post, "/user/delete_account", @@ -957,7 +961,7 @@ export class LemmyHttp { * * `HTTP.POST /user/password_reset` */ - async passwordReset(form: PasswordReset) { + passwordReset(form: PasswordReset) { return this.wrapper( HttpType.Post, "/user/password_reset", @@ -970,7 +974,7 @@ export class LemmyHttp { * * `HTTP.POST /user/password_change` */ - async passwordChange(form: PasswordChange) { + passwordChange(form: PasswordChange) { return this.wrapper( HttpType.Post, "/user/password_change", @@ -983,7 +987,7 @@ export class LemmyHttp { * * `HTTP.POST /user/mark_all_as_read` */ - async markAllAsRead(form: MarkAllAsRead) { + markAllAsRead(form: MarkAllAsRead) { return this.wrapper( HttpType.Post, "/user/mark_all_as_read", @@ -996,7 +1000,7 @@ export class LemmyHttp { * * `HTTP.PUT /user/save_user_settings` */ - async saveUserSettings(form: SaveUserSettings) { + saveUserSettings(form: SaveUserSettings) { return this.wrapper( HttpType.Put, "/user/save_user_settings", @@ -1009,7 +1013,7 @@ export class LemmyHttp { * * `HTTP.PUT /user/change_password` */ - async changePassword(form: ChangePassword) { + changePassword(form: ChangePassword) { return this.wrapper( HttpType.Put, "/user/change_password", @@ -1022,7 +1026,7 @@ export class LemmyHttp { * * `HTTP.GET /user/report_count` */ - async getReportCount(form: GetReportCount) { + getReportCount(form: GetReportCount) { return this.wrapper( HttpType.Get, "/user/report_count", @@ -1035,7 +1039,7 @@ export class LemmyHttp { * * `HTTP.GET /user/unread_count` */ - async getUnreadCount(form: GetUnreadCount) { + getUnreadCount(form: GetUnreadCount) { return this.wrapper( HttpType.Get, "/user/unread_count", @@ -1048,7 +1052,7 @@ export class LemmyHttp { * * `HTTP.POST /user/verify_email` */ - async verifyEmail(form: VerifyEmail) { + verifyEmail(form: VerifyEmail) { return this.wrapper( HttpType.Post, "/user/verify_email", @@ -1061,7 +1065,7 @@ export class LemmyHttp { * * `HTTP.POST /admin/add` */ - async addAdmin(form: AddAdmin) { + addAdmin(form: AddAdmin) { return this.wrapper( HttpType.Post, "/admin/add", @@ -1074,7 +1078,7 @@ export class LemmyHttp { * * `HTTP.GET /admin/registration_application/count` */ - async getUnreadRegistrationApplicationCount( + getUnreadRegistrationApplicationCount( form: GetUnreadRegistrationApplicationCount ) { return this.wrapper< @@ -1088,7 +1092,7 @@ export class LemmyHttp { * * `HTTP.GET /admin/registration_application/list` */ - async listRegistrationApplications(form: ListRegistrationApplications) { + listRegistrationApplications(form: ListRegistrationApplications) { return this.wrapper< ListRegistrationApplications, ListRegistrationApplicationsResponse @@ -1100,7 +1104,7 @@ export class LemmyHttp { * * `HTTP.PUT /admin/registration_application/approve` */ - async approveRegistrationApplication(form: ApproveRegistrationApplication) { + approveRegistrationApplication(form: ApproveRegistrationApplication) { return this.wrapper< ApproveRegistrationApplication, RegistrationApplicationResponse @@ -1112,7 +1116,7 @@ export class LemmyHttp { * * `HTTP.POST /admin/purge/person` */ - async purgePerson(form: PurgePerson) { + purgePerson(form: PurgePerson) { return this.wrapper( HttpType.Post, "/admin/purge/person", @@ -1125,7 +1129,7 @@ export class LemmyHttp { * * `HTTP.POST /admin/purge/community` */ - async purgeCommunity(form: PurgeCommunity) { + purgeCommunity(form: PurgeCommunity) { return this.wrapper( HttpType.Post, "/admin/purge/community", @@ -1138,7 +1142,7 @@ export class LemmyHttp { * * `HTTP.POST /admin/purge/post` */ - async purgePost(form: PurgePost) { + purgePost(form: PurgePost) { return this.wrapper( HttpType.Post, "/admin/purge/post", @@ -1151,7 +1155,7 @@ export class LemmyHttp { * * `HTTP.POST /admin/purge/comment` */ - async purgeComment(form: PurgeComment) { + purgeComment(form: PurgeComment) { return this.wrapper( HttpType.Post, "/admin/purge/comment", @@ -1186,7 +1190,52 @@ export class LemmyHttp { return this.wrapper(HttpType.Post, "/custom_emoji/delete", form); } - private buildFullUrl(endpoint: string): string { + /** + * Upload an image to the server. + */ + async uploadImage({ + image, + auth, + }: UploadImage): Promise { + const formData = createFormData(image); + + // If jwt cookie not already set by browser, set it with passed in auth + const headers = {} as any; + if ( + !globalThis?.document?.cookie?.includes("jwt=") && + !this.headers?.Cookie?.includes("jwt=") + ) { + headers.Cookie = `jwt=${auth}`; + } + + let url: string | undefined = undefined; + let delete_url: string | undefined = undefined; + + const response = await fetch(this.pictrsUrl, { + method: HttpType.Post, + body: formData as unknown as BodyInit, + headers: { + ...this.headers, + ...headers, + }, + }); + + const responseJson = await response.json(); + + if (responseJson.msg === "ok") { + const { file: hash, delete_token: deleteToken } = responseJson.files[0]; + delete_url = `${this.pictrsUrl}/delete/${deleteToken}/${hash}`; + url = `${this.pictrsUrl}/${hash}`; + } + + return { + ...responseJson, + url, + delete_url, + }; + } + + private buildFullUrl(endpoint: string) { return `${this.apiUrl}${endpoint}`; } @@ -1195,21 +1244,25 @@ export class LemmyHttp { endpoint: string, form: BodyType ): Promise { - if (type_ == HttpType.Get) { - let getUrl = `${this.buildFullUrl(endpoint)}?${encodeGetParams(form)}`; - return fetch(getUrl, { - method: "GET", + if (type_ === HttpType.Get) { + const getUrl = `${this.buildFullUrl(endpoint)}?${encodeGetParams(form)}`; + const response = await fetch(getUrl, { + method: HttpType.Get, headers: this.headers, - }).then(d => d.json() as Promise); + }); + + return await response.json(); } else { - return fetch(this.buildFullUrl(endpoint), { + const response = await fetch(this.buildFullUrl(endpoint), { method: type_, headers: { "Content-Type": "application/json", ...this.headers, }, body: JSON.stringify(form), - }).then(d => d.json() as Promise); + }); + + return await response.json(); } } } @@ -1220,3 +1273,16 @@ function encodeGetParams(p: BodyType): string { .map(kv => kv.map(encodeURIComponent).join("=")) .join("&"); } + +function createFormData(image: File | Buffer): FormData { + let formData = new FormData(); + + if (image.constructor.name === "File") { + formData.append("images[]", image); + } else { + // The filename doesn't affect the file type or file name that ends up in pictrs + formData.append("images[]", image, { filename: "image.jpg" }); + } + + return formData; +} diff --git a/src/interfaces/others.ts b/src/interfaces/others.ts index f1a306c..59824c5 100644 --- a/src/interfaces/others.ts +++ b/src/interfaces/others.ts @@ -233,3 +233,26 @@ export interface SiteMetadata { image?: string; html?: string; } + +export interface UploadImage { + image: File | Buffer; + /** + * Optional if cookie with jwt set is already present. Otherwise, auth is required. + */ + auth?: string; +} + +export interface UploadImageResponse { + /** + * Is "ok" if the upload was successful; is something else otherwise. + */ + msg: string; + files?: ImageFile[]; + url?: string; + delete_url?: string; +} + +export interface ImageFile { + file: string; + delete_token: string; +} diff --git a/tsconfig.json b/tsconfig.json index 67a72e7..61b8f21 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,10 +9,9 @@ "target": "ES5", "experimentalDecorators": true, "strictNullChecks": true, - "moduleResolution": "Node" + "moduleResolution": "Node", + "esModuleInterop": true }, - "include": [ - "src/**/*" - ], + "include": ["src/**/*"], "exclude": ["node_modules", "dist"] } diff --git a/yarn.lock b/yarn.lock index 6ae092d..d0db72e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -303,14 +303,6 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== -"@types/node-fetch@2.6.2": - version "2.6.2" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.2.tgz#d1a9c5fd049d9415dce61571557104dec3ec81da" - integrity sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A== - dependencies: - "@types/node" "*" - form-data "^3.0.0" - "@types/node@*", "@types/node@^18.6.2": version "18.11.18" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f" @@ -665,6 +657,13 @@ cosmiconfig@^5.0.5: js-yaml "^3.13.1" parse-json "^4.0.0" +cross-fetch@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" + integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== + dependencies: + node-fetch "2.6.7" + cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -988,10 +987,10 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== -form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" @@ -1513,10 +1512,10 @@ neo-async@^2.6.0: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -node-fetch@2.6.6: - version "2.6.6" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89" - integrity sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA== +node-fetch@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== dependencies: whatwg-url "^5.0.0" From be449fe39e3b4cde29a660a04ab3317ed074f9a8 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Mon, 27 Mar 2023 12:19:19 -0400 Subject: [PATCH 6/6] Add woodpecker (#110) * Adding woodpecker 1 * Adding woodpecker 2 * v0.17.2-rc.4 --- .drone.yml | 33 --------------------------------- .woodpecker.yml | 20 ++++++++++++++++++++ package.json | 2 +- 3 files changed, 21 insertions(+), 34 deletions(-) delete mode 100644 .drone.yml create mode 100644 .woodpecker.yml diff --git a/.drone.yml b/.drone.yml deleted file mode 100644 index 7c609fd..0000000 --- a/.drone.yml +++ /dev/null @@ -1,33 +0,0 @@ ---- -kind: pipeline -name: amd64 - -platform: - os: linux - arch: amd64 - -steps: - - - name: yarn - image: node:17-alpine - commands: - - yarn - - - name: yarn lint - image: node:17-alpine - commands: - - yarn lint - - - name: npm publish - image: node:17-alpine - commands: - - echo "//registry.npmjs.org/:_authToken=$NPM_AUTH_TOKEN" >> .npmrc - - echo "email = $NPM_EMAIL" >> ~/.npmrc - - npm publish - environment: - NPM_AUTH_TOKEN: - from_secret: npm_token - NPM_EMAIL: tyhou13@gmx.com - when: - ref: - - refs/tags/* diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 0000000..2ae7693 --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,20 @@ +pipeline: + yarn: + image: node:17-alpine + commands: + - yarn + + yarn_lint: + image: node:17-alpine + commands: + - yarn lint + + npm_publish: + image: node:17-alpine + commands: + - echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> .npmrc + - echo "email = tyhou13@gmx.com" >> ~/.npmrc + - npm publish + secrets: [npm_token] + when: + event: tag diff --git a/package.json b/package.json index 897e124..754ba16 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lemmy-js-client", - "version": "0.17.2-rc.3", + "version": "0.17.2-rc.4", "description": "A javascript / typescript client for Lemmy", "repository": "https://github.com/LemmyNet/lemmy-js-client", "license": "AGPL-3.0",