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

refector: 調整資料儲存格式跟collection path #8

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ DISCORD_TOKEN=<YOUR_BOT_TOKEN>
PUBLIC_KEY=<YOUR_PUBLIC_KEY>
DISCORD_GUILDID=<YOUR_DISCORD_GUILDID>
CHANNEL_ID=<BOT_SEND_MESSAGE_CHANNEL_ID>

QUESTION_DISCUSSION_CHANNEL=<QUESTION_DISCUSSION_CHANNEL>
PORT=
23 changes: 23 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
},
"dependencies": {
"cors": "^2.8.5",
"cron": "^3.0.0",
"discord.js": "^14.9.0",
"dotenv": "^16.0.3",
"express": "^4.18.2",
Expand Down
45 changes: 23 additions & 22 deletions src/apiServer/routes/leaderboard.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
const express = require('express');
const router = express.Router();
const Discord = require('discord.js');
const { client } = require('../../config/discordClient.js');

const { db } = require('../../config/db');
const { pageSize } = require('../../const.js');
const { defaultPageSize } = require('../../const.js');

function validate(req, res, next) {
const { date, discordId, page } = req.query;
const { year, month, discordId, page } = req.query;
if (page && typeof Number(page) && Number(page) <= 0) {
return res.status(400).json('page must be valid number');
}

const dateRegex = /([12]\d{3}-(0[1-9]|1[0-2]))/;
if (date && !dateRegex.test(date)) {
return res.status(400).json('date must be in YYYY-MM format');
if (!year || !month) {
return res.status(400).json('年跟月份為必填項');
}

const yearRegex = /^[1-9]\d{3}$/;
const monthRegex = /^(0?[1-9]|1[0-2])$/;
if (!yearRegex.test(year) || !monthRegex.test(month)) {
return res.status(400).json({ message: '年或月份為非法格式', year, month });
}

if (discordId && typeof discordId !== 'string') {
Expand All @@ -23,14 +28,17 @@ function validate(req, res, next) {
next();
}



router.get('/', validate, async function (req, res) {
const currentYearAndMonth = new Date().toISOString().slice(0, 7);
const { date, discordId, page = 1 } = req.query;
const {
year,
month,
discordId,
page = 1,
pageSize = defaultPageSize
} = req.query;
let ref = db
.collection(`leaderboard-${currentYearAndMonth}`)
.where('period', '=', date || currentYearAndMonth);
.collection(`leaderboard-${year}`)
.where('month', '=', Number(month));

const countSnapshot = await ref.count().get();
const totalDocsCount = countSnapshot.data().count;
Expand All @@ -40,18 +48,12 @@ router.get('/', validate, async function (req, res) {
if (discordId) {
ref = ref.where('discordId', '=', discordId);
}

const querySnapshot = await ref
.orderBy('point', 'desc')
.limit(pageSize)
.limit(Number(pageSize))
.offset(offset)
.get();

const client = new Discord.Client({
intents: []
});
client.login(process.env.DISCORD_TOKEN);

const fetchUserDetails = async (doc) => {
const data = doc.data();
const guild = await client.guilds.fetch(process.env.DISCORD_GUILDID);
Expand All @@ -67,13 +69,12 @@ router.get('/', validate, async function (req, res) {

const promises = querySnapshot.docs.map(fetchUserDetails);
const results = await Promise.all(promises);

return res.success({
data: results,
offset,
pageSize,
pageSize: Number(pageSize),
totalPages,
currentPage: page,
currentPage: Number(page),
totalDataCount: totalDocsCount
});
});
Expand Down
71 changes: 33 additions & 38 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,16 @@
require('dotenv').config();
const { readdirSync } = require('node:fs');
const { join } = require('node:path');
const {
Client,
Collection,
GatewayIntentBits,
Events,
EmbedBuilder,
Partials
} = require('discord.js');
const { client } = require('./config/discordClient.js');

client.login(process.env.DISCORD_TOKEN);

const { Events, EmbedBuilder } = require('discord.js');
const { db } = require('./config/db.js');
const { FieldValue } = require('firebase-admin/firestore');
const logger = require('./lib/logger.js');

const fs = require('fs');
const path = require('path');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildMessageReactions
],
partials: [Partials.Message, Partials.Channel, Partials.Reaction]
});

client.commands = new Collection();

const eventsPath = join(__dirname, 'events');
const eventFiles = readdirSync(eventsPath).filter((file) =>
Expand Down Expand Up @@ -58,6 +44,19 @@ for (const file of commandFiles) {
}
}

client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}`);
console.log(`Channels cached: ${client.channels.cache.size}`);
require('./cronJob/index.js');
/**
* API Server Execution
*/
const ApiServer = require('./apiServer/apiServer.js');

const server = new ApiServer(process.env.PORT || 3306);
server.start();
});

client.on(Events.MessageReactionAdd, async (reaction, user) => {
// When a reaction is received, check if the structure is partial
if (reaction.partial) {
Expand All @@ -73,17 +72,21 @@ client.on(Events.MessageReactionAdd, async (reaction, user) => {

if (reaction.emoji.name === '🧡' && reaction.message.author !== user) {
const date = new Date();
const yearAndMonth = date.toISOString().slice(0, 7);
const collectionName = `leaderboard-${yearAndMonth}`;
const year = date.getFullYear();
const month = date.getMonth() + 1;
const collectionName = `leaderboard-${year}`;

await db.runTransaction(async (t) => {
const ref = db
.collection(collectionName)
.where('discordId', '=', reaction.message.author.id);
.where('discordId', '=', reaction.message.author.id)
.where('month', '==', month);

const snapshot = await t.get(ref);
if (snapshot.empty) {
t.set(db.collection(`leaderboard-${yearAndMonth}`).doc(), {
period: yearAndMonth,
t.set(db.collection(`leaderboard-${year}`).doc(), {
year,
month,
discordId: reaction.message.author.id,
point: 1
});
Expand Down Expand Up @@ -122,26 +125,18 @@ client.on(Events.MessageReactionRemove, async (reaction, user) => {
if (reaction.emoji.name === '🧡' && reaction.message.author !== user) {
await db.runTransaction(async (t) => {
const date = new Date();
const yearAndMonth = date.toISOString().slice(0, 7);
const collectionName = `leaderboard-${yearAndMonth}`;
const year = date.getFullYear();
const month = date.getMonth() + 1;
const collectionName = `leaderboard-${year}`;

const ref = db
.collection(collectionName)
.where('discordId', '=', reaction.message.author.id);
.where('discordId', '=', reaction.message.author.id)
.where('month', '==', month);
const snapshot = await t.get(ref);

!snapshot.empty &&
t.update(snapshot.docs[0].ref, { point: FieldValue.increment(-1) });
});
}
});

// Log in to Discord with your client's token
client.login(process.env.DISCORD_TOKEN);


/**
* API Server Execution
*/
const ApiServer = require('./apiServer/apiServer.js');
const server = new ApiServer(process.env.PORT || 3306);
server.start();
20 changes: 20 additions & 0 deletions src/config/discordClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const {
Client,
Collection,
GatewayIntentBits,
Partials
} = require('discord.js');

const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildMessageReactions
],
partials: [Partials.Message, Partials.Channel, Partials.Reaction]
});

client.commands = new Collection();
client.login(process.env.DISCORD_TOKEN);

module.exports = { client };
4 changes: 2 additions & 2 deletions src/const.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
const pageSize = 10;
module.exports = { pageSize };
const defaultPageSize = 10;
module.exports = { defaultPageSize };
3 changes: 3 additions & 0 deletions src/cronJob/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const { notifyBillboardJob } = require('./notifyBillboard');

notifyBillboardJob.start();
Loading