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

Feat/scheduled events #24

Merged
merged 5 commits into from
Jun 10, 2024
Merged
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 docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -16,6 +16,11 @@ RUN pnpm build

FROM node:20-alpine as runner

ENV TZ America/Sao_Paulo

RUN apk add --no-cache tzdata
RUN ln -s /usr/share/zoneinfo/${TZ} /etc/localtime

WORKDIR /app

COPY --from=builder /app/package.json ./
5 changes: 3 additions & 2 deletions docker/Dockerfile.backup
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
FROM alpine:latest

RUN apk add --no-cache sqlite curl tzdata tar
ENV TZ America/Sao_Paulo

ENV TZ=America/Sao_Paulo
RUN apk add --no-cache sqlite curl tzdata tar
RUN ln -s /usr/share/zoneinfo/${TZ} /etc/localtime

COPY scripts/backup.sh /usr/local/bin/backup.sh
COPY scripts/crontab /etc/crontabs/root
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -30,12 +30,13 @@
"typescript": "^5.4.5"
},
"dependencies": {
"prisma": "^5.14.0",
"@prisma/client": "5.14.0",
"@sapphire/discord.js-utilities": "^7.2.1",
"@sapphire/framework": "^5.2.1",
"@sapphire/pieces": "^4.2.2",
"cron": "^3.1.7",
"dayjs": "^1.11.11",
"discord.js": "14.x"
"discord.js": "14.x",
"prisma": "^5.14.0"
}
}
22 changes: 22 additions & 0 deletions pnpm-lock.yaml

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
Warnings:

- You are about to drop the column `date` on the `Events` table. All the data in the column will be lost.
- Added the required column `day` to the `Events` table without a default value. This is not possible if the table is not empty.
- Added the required column `month` to the `Events` table without a default value. This is not possible if the table is not empty.

*/
-- RedefineTables
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_Events" (
"id" TEXT NOT NULL PRIMARY KEY,
"description" TEXT NOT NULL,
"month" INTEGER NOT NULL,
"day" INTEGER NOT NULL,
"repeat" BOOLEAN NOT NULL DEFAULT false,
"guild_id" TEXT,
"created_by" TEXT,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" DATETIME NOT NULL,
CONSTRAINT "Events_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "Events_created_by_fkey" FOREIGN KEY ("created_by") REFERENCES "User" ("discord_id") ON DELETE SET NULL ON UPDATE CASCADE
);
INSERT INTO "new_Events" ("created_at", "created_by", "description", "guild_id", "id", "repeat", "updated_at") SELECT "created_at", "created_by", "description", "guild_id", "id", "repeat", "updated_at" FROM "Events";
DROP TABLE "Events";
ALTER TABLE "new_Events" RENAME TO "Events";
PRAGMA foreign_key_check("Events");
PRAGMA foreign_keys=ON;
27 changes: 27 additions & 0 deletions prisma/migrations/20240610010812_event_type/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
Warnings:

- Added the required column `type` to the `Events` table without a default value. This is not possible if the table is not empty.

*/
-- RedefineTables
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_Events" (
"id" TEXT NOT NULL PRIMARY KEY,
"description" TEXT NOT NULL,
"month" INTEGER NOT NULL,
"day" INTEGER NOT NULL,
"type" TEXT NOT NULL,
"repeat" BOOLEAN NOT NULL DEFAULT false,
"guild_id" TEXT,
"created_by" TEXT,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" DATETIME NOT NULL,
CONSTRAINT "Events_guild_id_fkey" FOREIGN KEY ("guild_id") REFERENCES "Guild" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "Events_created_by_fkey" FOREIGN KEY ("created_by") REFERENCES "User" ("discord_id") ON DELETE SET NULL ON UPDATE CASCADE
);
INSERT INTO "new_Events" ("created_at", "created_by", "day", "description", "guild_id", "id", "month", "repeat", "updated_at") SELECT "created_at", "created_by", "day", "description", "guild_id", "id", "month", "repeat", "updated_at" FROM "Events";
DROP TABLE "Events";
ALTER TABLE "new_Events" RENAME TO "Events";
PRAGMA foreign_key_check("Events");
PRAGMA foreign_keys=ON;
16 changes: 9 additions & 7 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -16,20 +16,22 @@ model User {
xp Int @default(0) @map("xp")
level Int @default(1) @map("level")
birthday DateTime? @map("birthday")
Events Events[] @relation("UserEvents")
events Events[] @relation("user_events")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
}

model Events {
id String @id @default(cuid()) @map("id")
description String @map("description")
date DateTime @map("date")
month Int @map("month")
day Int @map("day")
type String @map("type")
repeat Boolean @default(false) @map("repeat")
guildId String? @map("guild_id")
Guild Guild? @relation("GuildEvents", fields: [guildId], references: [id])
guild Guild? @relation("guild_events", fields: [guildId], references: [id])
createdBy String? @map("created_by")
User User? @relation("UserEvents", fields: [createdBy], references: [discordId])
user User? @relation("user_events", fields: [createdBy], references: [discordId])
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
}
@@ -39,15 +41,15 @@ model Daily {
day Int @default(0) @map("day")
afternoon Int @default(0) @map("afternoon")
night Int @default(0) @map("night")
Guild Guild[]
guild Guild[]
}

model Guild {
id String @id @default(cuid()) @map("id")
discordId String @unique @map("discord_id")
mainChannel String? @map("main_channel")
Events Events[] @relation("GuildEvents")
Daily Daily? @relation(fields: [dailyId], references: [id])
events Events[] @relation("guild_events")
daily Daily? @relation(fields: [dailyId], references: [id])
dailyId String? @map("daily_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
3 changes: 0 additions & 3 deletions src/commands/user/avatar.ts
Original file line number Diff line number Diff line change
@@ -58,8 +58,6 @@ export class AvatarCommand extends Command {
};

const userType = interaction.options.getString("type");
const avatarType =
userType === "user" || !member.avatar ? "Usuário" : "Servidor";
const avatar =
userType === "user"
? member.user.displayAvatarURL(config)
@@ -68,7 +66,6 @@ export class AvatarCommand extends Command {
const embed = new EmbedBuilder()
.setTitle(nickname)
.setImage(avatar)
.setFooter({ text: avatarType })
.setColor(color);

await interaction.reply({
58 changes: 58 additions & 0 deletions src/events/announceScheduledEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { container } from "@sapphire/pieces";
import type { TextChannel } from "discord.js";

type ChannelMessage = {
channel: TextChannel;
message: string[];
};

export default async function announceScheduledEvent() {
const today = new Date();
const events = await container.db.events.findMany({
where: {
month: today.getMonth() + 1,
day: today.getDate(),
type: "DEFAULT",
},
include: {
guild: true,
},
});

if (!events || events.length <= 0) return;

const guilds = container.client.guilds.cache;
const channelMessages = new Map<string, ChannelMessage>();

for (const event of events) {
if (!event.guildId || !event.guild?.mainChannel) continue;

const guild = guilds.get(event.guild.discordId);
const channel = guild?.channels.cache.get(event.guild.mainChannel) as
| TextChannel
| undefined;

if (!channel || !guild) continue;

if (channelMessages.has(channel.id)) {
const messages = channelMessages.get(channel.id)?.message;
messages?.push(event.description);
} else {
channelMessages.set(channel.id, {
channel,
message: [event.description],
});
}

if (!event.repeat) {
await container.db.events.delete({ where: { id: event.id } });
}
}

for (const channelMessage of channelMessages.values()) {
const channel = channelMessage.channel;
channel.send(
`# Eventos\n${channelMessage.message.map((m) => `- ${m}`).join("\n")}`,
);
}
}
7 changes: 4 additions & 3 deletions src/events/giveXp.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { container } from "@sapphire/pieces";
import type { Message } from "discord.js";
import type { Message, TextChannel } from "discord.js";

export default function giveXp(message: Message) {
const member = message.member;
const guild = message.guild;
const channel = message.channel as TextChannel;

if (!member || !guild) return;
if (!member || !guild || !channel) return;

container.expHandler.addExp(member, guild);
container.expHandler.addExp(member, guild, channel);
}
15 changes: 15 additions & 0 deletions src/events/startTimers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { defaultTimeZone } from "@/utils/contants.js";
import { CronJob } from "cron";
import announceScheduledEvent from "./announceScheduledEvent.js";

export default function startTimers() {
new CronJob(
"* * * * *",
() => {
announceScheduledEvent();
},
null,
true,
defaultTimeZone,
);
}
2 changes: 1 addition & 1 deletion src/events/supressUrlEmbeds.ts
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ import type { Message } from "discord.js";
export default async function suppressUrlEmbeds(message: Message) {
const content = message.content;

if (!message.embeds.length) return;
if (message.embeds.length <= 0) return;

for (const url in urlFixers) {
if (content.includes(url)) {
5 changes: 4 additions & 1 deletion src/listeners/ready.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import startTimers from "@/events/startTimers.js";
import { Listener } from "@sapphire/framework";
import type { Client } from "discord.js";

@@ -13,5 +14,7 @@ export class ReadyListener extends Listener {
});
}

public run(client: Client) {}
public run(client: Client) {
startTimers();
}
}
7 changes: 5 additions & 2 deletions src/structures/xpHandler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ExpValues } from "@/utils/contants.js";
import { container } from "@sapphire/pieces";
import type { Guild, GuildMember } from "discord.js";
import type { Guild, GuildMember, TextChannel } from "discord.js";

export type ExpStats = {
exp: number;
@@ -53,7 +53,7 @@ export default class ExpHandler {
};
}

public async addExp(member: GuildMember, guild: Guild) {
public async addExp(member: GuildMember, guild: Guild, channel: TextChannel) {
const expStats = await this.getStats(member, guild);

if (!expStats?.canGetExp) return;
@@ -67,6 +67,9 @@ export default class ExpHandler {
if (expStats.exp >= xpRequired) {
expStats.level++;
expStats.exp = Math.max(newXp - xpRequired, 0);
channel.send(
`${member.toString()} subiu para o nível ${expStats.level}!`,
);
}

await container.db.user.upsert({
2 changes: 2 additions & 0 deletions src/utils/contants.ts
Original file line number Diff line number Diff line change
@@ -3,6 +3,8 @@ export const EmbedColors = {
anilist: 0x3db4f2,
};

export const defaultTimeZone = "America/Sao_Paulo";

export const leaderboardIcon = "https://i.imgur.com/qpb2q9S.png";

export const leaderboardEmojis = ["🥇", "🥈", "🥉"];
6 changes: 3 additions & 3 deletions src/utils/dateFormat.ts
Original file line number Diff line number Diff line change
@@ -20,9 +20,9 @@ export function dateToCron(dateStr: string) {

export function formatDate(date: DateObject): string {
const parts = [
String(date.day).padStart(2, "0"),
String(date.month).padStart(2, "0"),
String(date.year),
date.day ? String(date.day).padStart(2, "0") : undefined,
date.month ? String(date.month).padStart(2, "0") : undefined,
date.year ? String(date.year) : undefined,
].filter((part) => part);

return parts.join("/");