Skip to content

Commit d11e3cd

Browse files
committed
chore: attempt has been made
1 parent e9a4901 commit d11e3cd

22 files changed

+1156
-3556
lines changed

Makefile

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
deploy:
2+
docker-compose -f docker-compose.production.yml up -d --build
3+

STRATEGY.md

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# ShipID Verification Strategy
2+
3+
1. Live chat presense
4+
2. Membership joining message presense (Work in progress)
5+
3. Milestone message presense (Work in progress)
6+
4. Comment presense (Work in progress)
7+
8+
We suppose having `LIFETIME` variable with `1 week`.
9+
If user's last verification date is older than `LIFETIME` or never been verified before, verification process will commence.
10+
11+
## Verification
12+
13+
- Search live chats posted by the user within `LIFETIME` time range
14+
- If one of the chats has a valid membership badge, the user will be verified.
15+
- Otherwise, go to the next step
16+
- Search membership joining message or milestone message of the user within `LIFETIME` time range
17+
- If one of them exists, the user will be verified
18+
- Otherwise, go to the next step
19+
- Ask the user to provide the permalink of the video comment the user has posted on the video
20+
- If the comment has a valid membership badge, the user will be verified
21+
- After 24 hours without a response, go to the next step
22+
- Retry livechat strats once again
23+
- If verification is successful, the process is complete
24+
- Otherwise, go to the next step
25+
- Delete members-only role from the user
26+

docker-compose.development.yml docker-compose.production.yml

+11-9
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,22 @@ version: "3.1"
33
services:
44
mongo:
55
image: mongo:4
6+
restart: unless-stopped
67
volumes:
78
- ./data/mongo:/data/db
89

910
bot:
1011
build: .
11-
command: yarn dev
12-
ports:
13-
- "3000:3000"
14-
volumes:
15-
- ./lib:/app/lib
16-
- ./src:/app/src
12+
restart: unless-stopped
13+
command: node .
1714
env_file: .env
1815
environment:
1916
MONGODB_URL: mongodb://mongo:27017/shipid
20-
DEBUG: shipid
21-
depends_on:
22-
- mongo
17+
NODE_ENV: production
18+
networks:
19+
- default
20+
- webproxy
21+
22+
networks:
23+
webproxy:
24+
external: true

docker-compose.yml

+9-11
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,20 @@ version: "3.1"
33
services:
44
mongo:
55
image: mongo:4
6-
restart: unless-stopped
76
volumes:
87
- ./data/mongo:/data/db
98

109
bot:
1110
build: .
12-
restart: unless-stopped
13-
command: node .
11+
command: yarn dev
12+
ports:
13+
- "3000:3000"
14+
volumes:
15+
- ./lib:/app/lib
16+
- ./src:/app/src
1417
env_file: .env
1518
environment:
1619
MONGODB_URL: mongodb://mongo:27017/shipid
17-
NODE_ENV: production
18-
networks:
19-
- default
20-
- webproxy
21-
22-
networks:
23-
webproxy:
24-
external: true
20+
DEBUG: shipid
21+
depends_on:
22+
- mongo

jest.config.js

-4
This file was deleted.

package.json

+33-33
Original file line numberDiff line numberDiff line change
@@ -2,58 +2,58 @@
22
"name": "shipid",
33
"description": "Fully-automated YouTube Membership Verification Bot",
44
"version": "0.0.0",
5-
"author": "Yasuaki Uechi <[email protected]> (https://uechi.io/)",
5+
"author": "Yasuaki Uechi <[email protected]> (https://uechi.io)",
66
"scripts": {
77
"build": "tsc",
8-
"clean": "shx rm -rf lib && docker-compose down --rmi local",
9-
"deploy-commands": "ts-node src/modules/discord/deploy-commands.ts",
8+
"clean": "shx rm -rf lib && docker-compose -f docker-compose.production.yml down --rmi local",
9+
"deploy-commands": "ts-node src/discord/deploy-commands.ts",
1010
"dev": "run-p dev:*",
11+
"dev:prisma": "nodemon -w prisma/schema.prisma -x prisma generate",
1112
"dev:server": "nodemon -w lib .",
1213
"dev:tsc": "tsc -w",
13-
"devcontainer": "docker-compose -f docker-compose.development.yml up | grep -v mongo_1",
14+
"devcontainer": "docker-compose up | grep -v mongo_1",
1415
"predevcontainer": "npm run deploy-commands",
1516
"prepare": "husky install",
16-
"start": "node .",
17-
"test": "jest"
17+
"start": "node ."
1818
},
1919
"main": "./lib/index.js",
2020
"files": [
2121
"lib"
2222
],
2323
"dependencies": {
24-
"@discordjs/builders": "^0.7.0",
25-
"@discordjs/rest": "^0.1.0-canary.0",
26-
"@typegoose/typegoose": "^8.2.0",
27-
"debug": "^4.3.2",
28-
"discord-api-types": "^0.24.0",
29-
"discord.js": "^13.2.0",
30-
"express": "^4.17.1",
24+
"@discordjs/builders": "^0.15.0",
25+
"@discordjs/rest": "^0.5.0",
26+
"@prisma/client": "^4.0.0",
27+
"@typegoose/typegoose": "^9.10.1",
28+
"debug": "^4.3.4",
29+
"discord-api-types": "^0.36.1",
30+
"discord.js": "^13.8.1",
31+
"express": "^4.18.1",
3132
"jsonwebtoken": "^8.5.1",
32-
"luxon": "^2.0.2",
33-
"mongoose": "~5.13.8",
34-
"node-fetch": "2",
35-
"node-schedule": "^2.0.0"
33+
"luxon": "^3.0.1",
34+
"mongoose": "~6.4.4",
35+
"node-fetch": "3.2.7",
36+
"node-schedule": "^2.1.0",
37+
"prisma": "^4.0.0"
3638
},
3739
"devDependencies": {
3840
"@types/debug": "^4.1.7",
3941
"@types/express": "^4.17.13",
40-
"@types/jest": "^27.0.2",
41-
"@types/jsonwebtoken": "^8.5.5",
42-
"@types/luxon": "^2.0.5",
43-
"@types/node": "^16.11.1",
44-
"@types/node-fetch": "2",
45-
"@types/node-schedule": "^1.3.2",
46-
"husky": "^7.0.2",
47-
"jest": "^27.3.1",
48-
"masterchat": "^0.13.0",
49-
"nodemon": "^2.0.14",
42+
"@types/jest": "^28.1.4",
43+
"@types/jsonwebtoken": "^8.5.8",
44+
"@types/luxon": "^2.3.2",
45+
"@types/node": "^18.0.3",
46+
"@types/node-fetch": "2.6.2",
47+
"@types/node-schedule": "^2.1.0",
48+
"husky": "^8.0.1",
49+
"masterchat": "^1.1.0",
50+
"nodemon": "^2.0.19",
5051
"npm-run-all": "^4.1.5",
51-
"prettier": "^2.4.1",
52-
"pretty-quick": "^3.1.1",
53-
"shx": "^0.3.3",
54-
"ts-jest": "^27.0.7",
55-
"ts-node": "^10.3.0",
56-
"typescript": "^4.4.4"
52+
"prettier": "^2.7.1",
53+
"pretty-quick": "^3.1.3",
54+
"shx": "^0.3.4",
55+
"ts-node": "^10.8.2",
56+
"typescript": "^4.7.4"
5757
},
5858
"homepage": "https://github.com/holodata/shipid",
5959
"repository": {

src/constants.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ import assert from "assert";
22

33
export const isDev = process.env.NODE_ENV !== "production";
44

5+
export const LIFETIME = Number(process.env.LIFETIME || 1);
6+
7+
export const JWT_SECRET = process.env.JWT_SECRET!;
8+
assert(JWT_SECRET);
9+
510
export const DISCORD_CLIENT_ID = process.env.DISCORD_CLIENT_ID!;
611
assert(DISCORD_CLIENT_ID, "DISCORD_TOKEN is missing");
712

@@ -14,9 +19,6 @@ assert(DISCORD_TOKEN, "DISCORD_TOKEN is missing");
1419
export const MONGODB_URL = process.env.MONGODB_URL!;
1520
if (!isDev) assert(MONGODB_URL, "MONGODB_URL is missing");
1621

17-
export const JWT_SECRET = process.env.JWT_SECRET!;
18-
assert(JWT_SECRET);
19-
2022
export const HB_MONGO_URI = process.env.HB_MONGO_URI!;
2123
if (!isDev) assert(HB_MONGO_URI);
2224

src/db.ts

+44-45
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
import GuildModel from "./models/guild";
1+
import PairModel, { Pair } from "./models/pair";
22
import UserModel, { User } from "./models/user";
3-
import VerificationModel, { Status } from "./models/verification";
3+
import CertificateModel, { Certificate } from "./models/certificate";
44

55
export async function getUserByDiscordId(discordId: string) {
66
return await UserModel.findOne({ discordId });
77
}
88

9-
export async function createOrUpdateUser(
10-
discordId: string,
11-
{ youtubeChannelId }: { youtubeChannelId: string }
12-
) {
9+
export async function createOrUpdateUser({
10+
discordId,
11+
youtubeChannelId,
12+
}: {
13+
discordId: string;
14+
youtubeChannelId: string;
15+
}) {
1316
const user = await getUserByDiscordId(discordId);
1417
if (user) {
1518
user.youtubeChannelId = youtubeChannelId;
@@ -24,64 +27,60 @@ export async function createOrUpdateUser(
2427
return newUser;
2528
}
2629

27-
export async function findOrCreateGuild(guildId: string) {
28-
const guild = await GuildModel.findOne({ guildId });
29-
if (guild) return guild;
30-
31-
const newGuild = await GuildModel.create({
32-
guildId,
33-
roleMaps: [],
34-
createdAt: new Date(),
35-
});
36-
37-
return newGuild;
30+
export async function createPair({
31+
guildId,
32+
roleId,
33+
originChannelId,
34+
}: {
35+
guildId: string;
36+
roleId: string;
37+
originChannelId: string;
38+
}): Promise<Pair> {
39+
const pair = await PairModel.create({ guildId, roleId, originChannelId });
40+
return pair;
3841
}
3942

40-
export async function getRoleMapsForGuild(guildId: string) {
41-
const guild = await GuildModel.findOne({ guildId });
42-
if (!guild) return undefined;
43-
44-
const roleMaps = guild.roleMaps;
45-
return roleMaps;
43+
export async function getPairsForGuild(guildId: string): Promise<Pair[]> {
44+
const pairs = await PairModel.find({ guildId });
45+
return pairs;
4646
}
4747

48-
export async function findVerification({
48+
export async function findCertificate({
4949
user,
5050
originChannelId,
5151
}: {
5252
user: User;
5353
originChannelId: string;
54-
}) {
55-
return await VerificationModel.findOne({ user, originChannelId });
54+
}): Promise<Certificate | null> {
55+
return await CertificateModel.findOne({ user, originChannelId });
5656
}
5757

58-
export interface ModifyVerificationOptions {
58+
export interface ModifyOptions {
5959
user: User;
6060
originChannelId: string;
61-
status: Status;
61+
valid: boolean;
62+
since?: string;
6263
}
6364

64-
export async function updateVerification({
65+
export async function createOrUpdateCertificate({
6566
user,
6667
originChannelId,
67-
status,
68-
}: ModifyVerificationOptions) {
69-
return await VerificationModel.updateOne(
70-
{ user, originChannelId },
71-
{
72-
status,
73-
}
74-
);
75-
}
68+
valid,
69+
since,
70+
}: ModifyOptions): Promise<Certificate> {
71+
const cert = await findCertificate({ user, originChannelId });
72+
if (cert) {
73+
cert.valid = valid;
74+
cert.since = since;
75+
return await cert.save();
76+
}
7677

77-
export async function saveVerification({
78-
user,
79-
originChannelId,
80-
status,
81-
}: ModifyVerificationOptions) {
82-
return await VerificationModel.create({
78+
const newCert = await CertificateModel.create({
8379
user,
8480
originChannelId,
85-
status,
81+
valid,
82+
since,
8683
});
84+
85+
return newCert;
8786
}

0 commit comments

Comments
 (0)