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

ci/biome #65

Merged
merged 12 commits into from
Oct 2, 2024
39 changes: 0 additions & 39 deletions .eslintrc.json

This file was deleted.

17 changes: 17 additions & 0 deletions .github/workflows/code_queality.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Code quality

on:
pull_request:

jobs:
quality:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Biome
uses: biomejs/setup-biome@v2
with:
version: latest
- name: Run Biome
run: biome ci .
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
ITSのディスコードサーバーで使用するbotです
開発前に管理者からクレデンシャルを受け取ってください


# Getting started

```bash
Expand Down
31 changes: 31 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.2/schema.json",
"vcs": {
"enabled": false,
"clientKind": "git",
"useIgnoreFile": false
},
"files": {
"ignoreUnknown": false,
"ignore": []
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"javascript": {
"formatter": {
"quoteStyle": "double"
}
}
}
2 changes: 2 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ yarn start
```

## コマンドのデプロイ

discord botは新たに作成したコマンドは、それ単体でデプロイされる必要があります。
以下のコマンドを実行することで、更新した/新たに作成されたコマンドをデプロイすることができます。

```
yarn run deploy-commands
```
9 changes: 0 additions & 9 deletions eslint.config.mjs

This file was deleted.

30 changes: 10 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,28 @@
"start": "nodemon --exec ts-node src/main.ts",
"test": "ts-node src/main.ts",
"deploy-commands": "ts-node src/deployCommands.ts",
"format": "prettier --write .",
"lint": "eslint --ignore-pattern .gitignore './**/*.{js,ts}'",
"lint:fix": "eslint --ignore-pattern .gitignore './**/*.{js,ts}' --fix"
"format": "biome format --write",
"lint": "biome lint --write",
"lint:fix": "eslint --ignore-pattern .gitignore './**/*.{js,ts}' --fix",
"check": "biome check --write"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@eslint/js": "^9.9.1",
"@biomejs/biome": "1.9.2",
"@types/uuid": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@typescript-eslint/parser": "^7.18.0",
"eslint": "^9.9.1",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-sort-keys-fix": "^1.1.2",
"eslint-plugin-typescript-sort-keys": "^3.2.0",
"eslint-plugin-unused-imports": "^4.1.3",
"globals": "^15.9.0",
"nodemon": "^3.1.4",
"prettier": "^3.3.3",
"nodemon": "^3.1.7",
"ts-node": "^10.9.2",
"typescript": "^5.5.4",
"typescript-eslint": "^7.18.0"
"typescript": "^5.6.2"
},
"dependencies": {
"cron": "^3.1.7",
"discord.js": "^14.15.3",
"discord.js": "^14.16.3",
"dotenv": "^16.4.5",
"firebase": "^10.13.1",
"firebase-admin": "^12.4.0",
"firebase": "^10.14.0",
"firebase-admin": "^12.6.0",
"uuid": "^10.0.0"
},
"packageManager": "yarn@4.2.2"
Expand Down
123 changes: 78 additions & 45 deletions src/commands/auth.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,43 @@
import { SlashCommandBuilder, CommandInteraction, Guild, Role, GuildMember } from "discord.js";
import { Command } from "../types/command";
import {
type CommandInteraction,
type Guild,
type GuildMember,
type Role,
SlashCommandBuilder,
} from "discord.js";
import type { UserRecord } from "firebase-admin/lib/auth/user-record";
import {
getMemberByDiscordId,
getMemberByEmail,
} from "../controllers/MemberController";
import Department from "../entities/department";
import { adminAuth } from "../infra/firebase";
import { getMemberByDiscordId, getMemberByEmail } from "../controllers/MemberController";
import { UserRecord } from "firebase-admin/lib/auth/user-record";
import createRoleIfNotFound from "../utils/createRoleNotFound";
import type { Command } from "../types/command";
import addRoleToMember from "../utils/addRoleToMember";
import Department from "../entities/department";
import createRoleIfNotFound from "../utils/createRoleNotFound";

import type Member from "../entities/member";
import authorizedRoleProperty from "../roles/authorized";
//以下は、ロールのimport
import biRole from "../roles/departments/bi";
import graduateRole from "../roles/departments/graduate";
import othersRole from "../roles/departments/others";
import csRole from "../roles/departments/cs";
import graduateRole from "../roles/departments/graduate";
import iaRole from "../roles/departments/ia";
import authorizedRoleProperty from "../roles/authorized";
import obogRole from "../roles/departments/obog";
import othersRole from "../roles/departments/others";
import unAuthorizedRoleProperty from "../roles/unAuthorized";
import Member from "../entities/member";

const authCommand: Command = {
data: new SlashCommandBuilder().setName("auth").setDescription("認証コマンド"),
data: new SlashCommandBuilder()
.setName("auth")
.setDescription("認証コマンド"),
execute: authCommandHandler,
};

async function authCommandHandler(interaction: CommandInteraction) {
//DMでは実行できないようにする
if (!interaction.guild) return await interaction.reply("このコマンドはサーバーでのみ実行可能です");
if (!interaction.guild)
return await interaction.reply("このコマンドはサーバーでのみ実行可能です");

// Firestoreからメンバー情報を取得
const member = await getMemberByDiscordId(interaction.user.id);
Expand All @@ -49,25 +62,40 @@ async function authCommandHandler(interaction: CommandInteraction) {
}

async function changeNickName(interaction: CommandInteraction, member: Member) {
const guild: Guild = interaction.guild!;
const guildMember: GuildMember = await guild.members.fetch(interaction.user.id);
const realName: string = member.name;
const guild = interaction.guild;
if (!guild) {
throw new Error("This command can only be used in a guild.");
}
const guildMember = await guild.members.fetch(interaction.user.id);
const realName = member.name;
await guildMember.setNickname(realName);
}

async function giveRoles(interaction: CommandInteraction) {
const user = await adminAuth.getUserByEmail(interaction.user.tag);
const guild: Guild = interaction.guild!;
const guildMember: GuildMember = await guild.members.fetch(interaction.user.id);

const guild = interaction.guild;
if (!guild) {
throw new Error("This command can only be used in a guild.");
}
const guildMember = await guild.members.fetch(interaction.user.id);
await giveAuthorizedRole(interaction, guild, guildMember);
await giveDepartmentRole(interaction, user, guildMember);
}

async function giveAuthorizedRole(interaction: CommandInteraction, guild: Guild, guildMember: GuildMember) {
async function giveAuthorizedRole(
interaction: CommandInteraction,
guild: Guild,
guildMember: GuildMember,
) {
try {
const authorizedRole: Role = await createRoleIfNotFound({ guild, customRole: authorizedRoleProperty });
const unAuthorizedRole: Role = await createRoleIfNotFound({ guild, customRole: unAuthorizedRoleProperty });
const authorizedRole: Role = await createRoleIfNotFound({
guild,
customRole: authorizedRoleProperty,
});
const unAuthorizedRole: Role = await createRoleIfNotFound({
guild,
customRole: unAuthorizedRoleProperty,
});

await guildMember.roles.add(authorizedRole);
await guildMember.roles.remove(unAuthorizedRole);
Expand All @@ -78,36 +106,41 @@ async function giveAuthorizedRole(interaction: CommandInteraction, guild: Guild,
}
}

async function giveDepartmentRole(interaction: CommandInteraction, userAccount: UserRecord, guildMember: GuildMember) {
const guild: Guild = interaction.guild!;
async function giveDepartmentRole(
interaction: CommandInteraction,
userAccount: UserRecord,
guildMember: GuildMember,
) {
const guild = interaction.guild;
if (!guild) {
throw new Error("Guild not found");
}

//認証用のアカウントから、メンバー情報を取得
const member: Member | undefined = await getMemberByEmail(userAccount.email!);
if (!userAccount.email) {
throw new Error("User email not found");
}

// 認証用のアカウントから、メンバー情報を取得
const member = await getMemberByEmail(userAccount.email);
if (!member) {
throw new Error("Member not found");
return;
}

//TODO: 要リファクタリング
switch (member.department) {
case Department.CS:
await addRoleToMember(guild, guildMember, csRole);
break;
case Department.IA:
await addRoleToMember(guild, guildMember, iaRole);
break;
case Department.BI:
await addRoleToMember(guild, guildMember, biRole);
break;
case Department.GRADUATE:
await addRoleToMember(guild, guildMember, graduateRole);
break;
case Department.OTHERS:
await addRoleToMember(guild, guildMember, othersRole);
break;
default:
throw new Error("Department not found");
const departmentRoleMap = {
[Department.CS]: csRole,
[Department.IA]: iaRole,
[Department.BI]: biRole,
[Department.GRADUATE]: graduateRole,
[Department.OTHERS]: othersRole,
[Department.OBOG]: obogRole, // OBOGロールを追加
};

const role = departmentRoleMap[member.department];
if (!role) {
throw new Error("Department not found");
}

await addRoleToMember(guild, guildMember, role);
}

export default authCommand;
8 changes: 5 additions & 3 deletions src/commands/health_check.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { SlashCommandBuilder, CommandInteraction } from "discord.js";
import { Command } from "../types/command";
import { type CommandInteraction, SlashCommandBuilder } from "discord.js";
import type { Command } from "../types/command";

const healthCheckCommand: Command = {
data: new SlashCommandBuilder().setName("health_check").setDescription("ヘルスチェックコマンド"),
data: new SlashCommandBuilder()
.setName("health_check")
.setDescription("ヘルスチェックコマンド"),
async execute(interaction: CommandInteraction) {
await interaction.reply("I am healthy!");
},
Expand Down
30 changes: 23 additions & 7 deletions src/commands/hotChannel.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,32 @@
import { SlashCommandBuilder, CommandInteraction } from "discord.js";
import { Command } from "../types/command";
import { type CommandInteraction, SlashCommandBuilder } from "discord.js";
import type { Command } from "../types/command";
import { generateChannelActivityRanking } from "../usecases/getHotChannels";
import checkIsAdmin from "../utils/checkMemberRole";

const hotChannelsCommand: Command = {
data: new SlashCommandBuilder().setName("hot_channels").setDescription("Show hot channels ranking"),
data: new SlashCommandBuilder()
.setName("hot_channels")
.setDescription("Show hot channels ranking"),

async execute(interaction: CommandInteraction) {
if (!interaction.guild) return await interaction.reply("このコマンドはサーバーでのみ実行可能です");
if (!interaction.guild) {
await interaction.reply("このコマンドはサーバーでのみ実行可能です");
return;
}

const isAdmin: boolean = await checkIsAdmin(interaction);
if (!isAdmin) return await interaction.reply("このコマンドは管理者のみ使用可能です");
const ranking = await generateChannelActivityRanking(interaction.guild!);
await interaction.reply({ embeds: [ranking] });
if (!isAdmin) {
await interaction.reply("このコマンドは管理者のみ使用可能です");
return;
}

try {
const ranking = await generateChannelActivityRanking(interaction.guild);
await interaction.reply({ embeds: [ranking] });
} catch (error) {
console.error("Error generating channel activity ranking:", error);
await interaction.reply("ランキングの生成中にエラーが発生しました。");
}
},
};

Expand Down
Loading