forked from thislooksfun/snoots
-
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.
feat: add initial support for interacting with users
- Loading branch information
1 parent
5073ec4
commit bd0fc8b
Showing
8 changed files
with
539 additions
and
1 deletion.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
export { default as BaseControls } from "./base"; | ||
export { default as SubredditControls } from "./subreddit"; | ||
export { default as UserControls } from "./user"; | ||
export { default as VoteableControls } from "./voteable"; | ||
export { default as CommentControls } from "./comment"; | ||
export { default as PostControls } from "./post"; |
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,94 @@ | ||
import type { _Listing } from "../listings/listing"; | ||
import type { Comment, Post } from ".."; | ||
import type { Data, PostSort, RedditObject } from "../helper/types"; | ||
import type { MyUserData, OtherUserData, UserData } from "../objects/user"; | ||
import type Client from "../client"; | ||
import type Listing from "../listings/listing"; | ||
import { camelCaseKeys, assertKind } from "../helper/util"; | ||
import { fakeListingAfter } from "../listings/util"; | ||
import { MyUser, OtherUser, User } from "../objects/user"; | ||
import BaseControls from "./base"; | ||
import CommentListing from "../listings/comment"; | ||
import PostListing from "../listings/post"; | ||
|
||
/** | ||
* Various methods to allow you to interact with users. | ||
* | ||
* @category Controls | ||
*/ | ||
export default class UserControls extends BaseControls { | ||
/** @internal */ | ||
constructor(client: Client) { | ||
super(client, "u/"); | ||
} | ||
|
||
/** | ||
* Fetch a user from Reddit. | ||
* | ||
* @note If the username you fetch is the same as the authorized user this | ||
* will return a {@link MyUser} instance. Otherwise it will be an instance of | ||
* {@link OtherUser}. To tell dynamically you can use {@link User.isMe}. | ||
* | ||
* @param username The name of the user to fetch. | ||
* | ||
* @returns The user. | ||
*/ | ||
async fetch(username: string): Promise<User> { | ||
const res: RedditObject = await this.client.get(`user/${username}/about`); | ||
return this.fromRaw(res); | ||
} | ||
|
||
/** | ||
* Fetch the details of the authorized user. | ||
* | ||
* @returns The user. | ||
*/ | ||
async fetchMe(): Promise<MyUser> { | ||
const res: Data = await this.client.get("api/v1/me"); | ||
// /me doesn't return a wrapped object, so we have to make it ourselves. | ||
const raw: RedditObject = { kind: "t2", data: res }; | ||
return this.fromRaw(raw) as MyUser; | ||
} | ||
|
||
/** | ||
* Get a Listing of all the posts a user has made. | ||
* | ||
* @param user The user to get posts from. | ||
* @param sort How to sort the posts. | ||
* | ||
* @returns A sorted Listing of posts. | ||
*/ | ||
getPosts(user: string, sort: PostSort): Listing<Post> { | ||
const req = { url: `user/${user}/submitted`, query: { sort } }; | ||
const ctx = { req, client: this.client }; | ||
return new PostListing(fakeListingAfter(""), ctx); | ||
} | ||
|
||
/** | ||
* Get a Listing of all the comments a user has made. | ||
* | ||
* @param user The user to get comments from. | ||
* @param sort How to sort the comments. | ||
* | ||
* @returns A sorted Listing of comments. | ||
*/ | ||
getSortedComments(user: string, sort: string = "new"): Listing<Comment> { | ||
const req = { url: `user/${user}/comments`, query: { sort } }; | ||
const ctx = { req, client: this.client }; | ||
return new CommentListing(fakeListingAfter(""), ctx); | ||
} | ||
|
||
/** @internal */ | ||
fromRaw(raw: RedditObject): User { | ||
assertKind("t2", raw); | ||
|
||
const rDat = raw.data; | ||
const data: UserData = camelCaseKeys(rDat); | ||
|
||
if ("coins" in rDat) { | ||
return new MyUser(this, data as MyUserData); | ||
} else { | ||
return new OtherUser(this, data as OtherUserData); | ||
} | ||
} | ||
} |
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,161 @@ | ||
import type { PostSort } from "../../helper/types"; | ||
import type { UserControls } from "../../controls"; | ||
import { Comment, Content, ContentData, Post, Subreddit } from ".."; | ||
import Listing from "../../listings/listing"; | ||
|
||
// TODO: Suspended users give back a very minimal response. | ||
// BODY: Fetching a suspended user gives back very minimal data, meaning that | ||
// BODY: this typing below is only a valid base for non-suspended users. I'm not | ||
// BODY: sure what the best way to deal with this is... | ||
|
||
/** The data for a single Reddit user. */ | ||
export interface UserData extends ContentData { | ||
/** The amount of karma this user has gotten from getting awards. */ | ||
awardeeKarma: number; | ||
|
||
/** The amount of karma this user has gotten from giving awards. */ | ||
awarderKarma: number; | ||
|
||
/** The total karma this user has gotten from comments. */ | ||
commentKarma: number; | ||
|
||
/** Whether or not this user has subscribed to at least one subreddit. */ | ||
hasSubscribed: boolean; | ||
|
||
/** Whether or not this user has a verified email. */ | ||
hasVerifiedEmail: boolean; | ||
|
||
/** Whether or not this user should be hidden from search engine crawlers. */ | ||
hideFromRobots: boolean; | ||
|
||
/** The URL of this user's avatar image. */ | ||
iconImg: string; | ||
|
||
/** Whether or not this user is a Reddit employee. */ | ||
isEmployee: boolean; | ||
|
||
/** | ||
* Whether or not this user is a friend of the authorized user. | ||
* | ||
* @note This is only provided if you use {@link UserControls.fetch}, *not* if | ||
* you use {@link UserControls.fetchMe}. | ||
*/ | ||
isFriend?: boolean; | ||
|
||
/** Whether or not this user currently has Reddit Premium */ | ||
isGold: boolean; | ||
|
||
/** Whether or not this user is a moderator somewhere on Reddit. */ | ||
isMod: boolean; | ||
|
||
/** The total karma this user has gotten from posts. */ | ||
linkKarma: number; | ||
|
||
/** The user's name. */ | ||
name: string; | ||
|
||
/** The total karma this user has. */ | ||
totalKarma: number; | ||
|
||
/** Whether or not this user is verified. ??? */ | ||
verified: boolean; | ||
} | ||
|
||
/** | ||
* Any Reddit user. | ||
* | ||
* If you need more information you can cast to either {@link MyUser} or, more | ||
* likely {@link OtherUser}. See {@link isMe} for more information. | ||
*/ | ||
export abstract class User extends Content implements UserData { | ||
/** | ||
* Whether this user is the authorized user (instanceof {@link MyUser}) or not | ||
* (instanceof {@link OtherUser}). | ||
*/ | ||
abstract isMe: boolean; | ||
|
||
awardeeKarma: number; | ||
awarderKarma: number; | ||
commentKarma: number; | ||
hasSubscribed: boolean; | ||
hasVerifiedEmail: boolean; | ||
hideFromRobots: boolean; | ||
iconImg: string; | ||
isEmployee: boolean; | ||
isFriend?: boolean; | ||
isGold: boolean; | ||
isMod: boolean; | ||
linkKarma: number; | ||
name: string; | ||
totalKarma: number; | ||
verified: boolean; | ||
|
||
protected controls: UserControls; | ||
|
||
/** @internal */ | ||
constructor(controls: UserControls, data: UserData) { | ||
super(data); | ||
this.controls = controls; | ||
|
||
this.awardeeKarma = data.awardeeKarma; | ||
this.awarderKarma = data.awarderKarma; | ||
this.commentKarma = data.commentKarma; | ||
this.hasSubscribed = data.hasSubscribed; | ||
this.hasVerifiedEmail = data.hasVerifiedEmail; | ||
this.hideFromRobots = data.hideFromRobots; | ||
this.iconImg = data.iconImg; | ||
this.isEmployee = data.isEmployee; | ||
this.isFriend = data.isFriend; | ||
this.isGold = data.isGold; | ||
this.isMod = data.isMod; | ||
this.linkKarma = data.linkKarma; | ||
this.name = data.name; | ||
this.totalKarma = data.totalKarma; | ||
this.verified = data.verified; | ||
} | ||
|
||
/** | ||
* Re-fetch this user. | ||
* | ||
* Note: This returns a _new object_, it is _not_ mutating. | ||
* | ||
* @returns A promise that resolves to the newly fetched user. | ||
*/ | ||
async refetch(): Promise<User> { | ||
return this.controls.fetch(this.name); | ||
} | ||
|
||
/** | ||
* Fetch the user subreddit for this user. | ||
* | ||
* @returns A promise that resolves to this user's subreddit. | ||
*/ | ||
async fetchSubreddit(): Promise<Subreddit> { | ||
// TODO: The user fetch does return some info about this subreddit, just not | ||
// enough to populate a full Subreddit instance. Is there some way we could | ||
// make use of that partial data? | ||
return this.controls.getClient().subreddits.fetch(`u_${this.name}`); | ||
} | ||
|
||
/** | ||
* Get a Listing of all the posts this user has made. | ||
* | ||
* @param sort How to sort the posts. | ||
* | ||
* @returns A sorted Listing of posts. | ||
*/ | ||
getPosts(sort: PostSort): Listing<Post> { | ||
return this.controls.getPosts(this.name, sort); | ||
} | ||
|
||
/** | ||
* Get a Listing of all the comments this user has made. | ||
* | ||
* @param sort How to sort the comments. | ||
* | ||
* @returns A sorted Listing of comments. | ||
*/ | ||
getSortedComments(sort: string = "new"): Listing<Comment> { | ||
return this.controls.getSortedComments(this.name, sort); | ||
} | ||
} |
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,3 @@ | ||
export * from "./base"; | ||
export * from "./myuser"; | ||
export * from "./otheruser"; |
Oops, something went wrong.