Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ [Discord] Broader support for urls #46

Merged
merged 4 commits into from
Mar 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lazy-doors-stare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'socialitejs': patch
---

Support more variations for Discord urls.
344 changes: 172 additions & 172 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@
"@beefchimi/typescript-config": "^0.0.9",
"@changesets/changelog-github": "^0.4.3",
"@changesets/cli": "^2.21.0",
"@types/node": "^17.0.19",
"@vitest/ui": "^0.5.3",
"@types/node": "^17.0.21",
"@vitest/ui": "^0.5.9",
"c8": "^7.11.0",
"vite": "^2.8.4",
"vite": "^2.8.5",
"vite-plugin-dts": "^0.9.9",
"vitest": "^0.5.3"
"vitest": "^0.5.9"
}
}
10 changes: 10 additions & 0 deletions src/capture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,13 @@ export const defaultUserMatcher = {
subdomain: /[^.]+/,
path: /[^/]+/,
};

// TODO: This should probably be re-located elsewhere
// https://github.com/beefchimi/socialite/issues/35
export const discordPreferredUrls = {
users: `https://discordapp.com/users/${profileReplacement.user}`,
channels: `https://discord.com/channels/${profileReplacement.user}`,
vanity: `https://discord.gg/${profileReplacement.user}`,
// TODO: This result should not be supported
default: `https://discord.com/${profileReplacement.user}`,
};
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ export {
filterNullishValuesFromObject,
filterNetworkProperties,
mergeRegExp,
getDiscordPreferredUrl,
getUrlGroups,
getUrlWithSubstitutions,
} from './utilities';

export {MatchUserSource, UrlCaptureId} from './types';
export type {
DiscordUrlCriteria,
UrlAnatomy,
SocialiteNetwork,
SocialiteProfile,
Expand Down
21 changes: 18 additions & 3 deletions src/networks/discord.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
import {profileReplacement} from '../capture';
import {discordPreferredUrls} from '../capture';
import type {SocialiteNetwork} from '../types';

// Discord is difficult to solve given Socialite's current design.
// There are essentially 3 different urls to support:
// 1. User profiles (discordapp.com/users/*)
// 2. Server/channel urls (discord.com/channels/{serverid}/{channelid})
// 3. Official vanity urls (discord.gg/*)
// Since we are not yet validating against a Top-level domain (.gg),
// any `discord` url validates as true and captures the `path`.
// This degrades the confidence provided by `users` or `channels`.

// TODO: Solve this problem by improving `preferredUrl` and parsing criteria.
// https://github.com/beefchimi/socialite/issues/35
export const discord: SocialiteNetwork = {
id: 'discord',
preferredUrl: `https://discordapp.com/users/${profileReplacement.user}`,
preferredUrl: discordPreferredUrls.users,
matcher: {
domain: /discord/,
user: /^(?:\/users\/)([^/]+)/,
user: /^\/(?:users\/|channels\/)?([^/]+)/,
// TODO: If we want to support capturing EVERYTHING after
// the first `/` (necessary for capturing the `channelid`),
// then we would need to use the following:
// user: /^\/(?:users\/|channels\/)?(.+)/,
},
};
120 changes: 98 additions & 22 deletions src/networks/tests/discord.test.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,114 @@
import {Socialite} from '../../socialite';
import type {SocialiteProfile} from '../../types';
import {allSocialiteNetworks, mockGenericUser} from '../../tests/fixtures';
import {
allSocialiteNetworks,
discordValidUrls,
mockGenericUser,
} from '../../tests/fixtures';
import {discord} from '../discord';

describe('Social networks > discord', () => {
const mockSocialite = new Socialite(allSocialiteNetworks);
const mockCommonUrl = `https://www.discordapp.com/users/${mockGenericUser}`;

it('returns expected `id` and `user` from common url', () => {
const {id, user} = mockSocialite.parseProfile(
mockCommonUrl,
) as SocialiteProfile;
// TODO: We want to resolve these in the future
// https://github.com/beefchimi/socialite/issues/35
describe('bogus', () => {
it('mistakenly returns the first path match for any `discord` url', () => {
const mockPageSlug = 'about-us-page';
const mockBogusUrl = `https://www.discord.com/${mockPageSlug}`;

expect(id).toBe(discord.id);
expect(user).toBe(mockGenericUser);
const {id, user} = mockSocialite.parseProfile(
mockBogusUrl,
) as SocialiteProfile;

expect(id).toBe(discord.id);
expect(user).toBe(mockPageSlug);
});
});

describe('users', () => {
const mockUsersUrl = `https://www.discordapp.com/users/${mockGenericUser}`;

it('returns `id` and `user`', () => {
const {id, user} = mockSocialite.parseProfile(
mockUsersUrl,
) as SocialiteProfile;

expect(id).toBe(discord.id);
expect(user).toBe(mockGenericUser);
});

it('omits any trailing path after the first `user` match', () => {
const mockUsersTrailingUrl = `${mockUsersUrl}/trail-123`;

const {id, user} = mockSocialite.parseProfile(
mockUsersTrailingUrl,
) as SocialiteProfile;

expect(id).toBe(discord.id);
expect(user).toBe(mockGenericUser);
});
});

it('returns expected `id` and `user` from url with trailing path', () => {
const mockUncommonUrl = `${mockCommonUrl}/trail-123`;
const {id, user} = mockSocialite.parseProfile(
mockUncommonUrl,
) as SocialiteProfile;
describe('channels', () => {
const mockChannelsUrl = `https://www.discord.com/channels/${mockGenericUser}`;

it('returns `id` and `user`', () => {
const {id, user} = mockSocialite.parseProfile(
mockChannelsUrl,
) as SocialiteProfile;

expect(id).toBe(discord.id);
expect(user).toBe(mockGenericUser);
});

it('omits any trailing path after the first `user` match', () => {
const mockChannelsTrailingUrl = `${mockChannelsUrl}/trail-123`;

const {id, user} = mockSocialite.parseProfile(
mockChannelsTrailingUrl,
) as SocialiteProfile;

expect(id).toBe(discord.id);
expect(user).toBe(mockGenericUser);
});
});

describe('vanity', () => {
const mockVanityUrl = `https://discord.gg/${mockGenericUser}`;

it('returns `id` and `user`', () => {
const {id, user} = mockSocialite.parseProfile(
mockVanityUrl,
) as SocialiteProfile;

expect(id).toBe(discord.id);
expect(user).toBe(mockGenericUser);
});

it('omits any trailing path after the first `user` match', () => {
const mockVanityTrailingUrl = `${mockVanityUrl}/trail-123`;

const {id, user} = mockSocialite.parseProfile(
mockVanityTrailingUrl,
) as SocialiteProfile;

expect(id).toBe(discord.id);
expect(user).toBe(mockGenericUser);
expect(id).toBe(discord.id);
expect(user).toBe(mockGenericUser);
});
});

it('returns `id` with no `user` when provided an unrecognized leading path', () => {
const mockUnsupportedUrl = `https://discordapp.com/foo/${mockGenericUser}`;
const match = mockSocialite.parseProfile(
mockUnsupportedUrl,
) as SocialiteProfile;
describe('all variations', () => {
it('returns `id` and `user`', () => {
discordValidUrls.forEach(({originalUrl, preferredUrl, user}) => {
const match = mockSocialite.parseProfile(
originalUrl,
) as SocialiteProfile;

expect(match.id).toBe(discord.id);
expect(match.user).toBeUndefined();
expect(match.id).toBe(discord.id);
expect(match.preferredUrl).toBe(preferredUrl);
expect(match.user).toBe(user);
});
});
});
});
17 changes: 12 additions & 5 deletions src/socialite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type {
} from './types';
import {
filterNetworkProperties,
getDiscordPreferredUrl,
getUrlGroups,
getUrlWithSubstitutions,
} from './utilities';
Expand Down Expand Up @@ -155,11 +156,17 @@ export class Socialite {
return minResult;
}

const preferredUrl = getUrlWithSubstitutions(
targetNetwork.preferredUrl,
user,
prefix,
);
// TODO: Resolve this special condition
// https://github.com/beefchimi/socialite/issues/35
const preferredUrl =
targetNetwork.id === 'discord'
? getDiscordPreferredUrl({
tldomain: minResult.urlGroups.tldomain,
path: minResult.urlGroups.path,
user,
})
: getUrlWithSubstitutions(targetNetwork.preferredUrl, user, prefix);

const appUrl = targetNetwork.appUrl
? getUrlWithSubstitutions(targetNetwork.appUrl, user, prefix)
: undefined;
Expand Down
Loading