Skip to content

Commit

Permalink
✨ 하루 5개 제한 (#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
woohm402 authored Jan 28, 2025
1 parent 2f5a236 commit b12010a
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 5 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ jobs:
run: bun tsc
- name: Check format & lint
run: bun check
- name: Test
run: bun test
3 changes: 3 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
"linter": {
"rules": {
"all": true,
"complexity": {
"noExcessiveCognitiveComplexity": "off"
},
"correctness": {
"noUndeclaredDependencies": "off",
"useImportExtensions": "off"
Expand Down
45 changes: 40 additions & 5 deletions src/services/SlackEventService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { AnyBlock, SlackEvent } from '@slack/web-api';
import type { SlackID } from '../entities/Slack';
import type { Log } from '../entities/Waffle';
import type { MessengerPresenter } from '../presenters/MessengerPresenter';
import { getTodayStartAsKST } from '../utils/getTodayStartAsKST';

type SlackEventService = {
handleEvent: (event: SlackEvent) => Promise<void>;
Expand All @@ -21,7 +22,10 @@ export const implementSlackEventService = ({
getPermalink: (_: { channel: string; ts: string }) => Promise<{ link: string }>;
sendMessage: (_: { channel: string; text: string; blocks: AnyBlock[] }) => Promise<void>;
};
waffleRepository: { insert: (_: Log[]) => Promise<void> };
waffleRepository: {
insert: (_: Log[]) => Promise<void>;
listLogs: (_: { from: Date; to: Date }) => Promise<{ logs: Log[] }>;
};
}): SlackEventService => {
return {
handleEvent: async (event) => {
Expand All @@ -47,19 +51,28 @@ export const implementSlackEventService = ({
}));
break;
case 'message': {
if (!('user' in event && typeof event.user === 'string' && event.subtype === undefined)) {
console.debug('skip message', JSON.stringify(event));
if (!('user' in event && typeof event.user === 'string' && event.subtype === undefined))
return;
}

const user = event.user as SlackID;
const todayGivenCount = (
await waffleRepository.listLogs({
from: getTodayStartAsKST(new Date()),
to: new Date(),
})
).logs
.filter((l) => l.from === user)
.reduce((a, c) => a + c.count, 0);
const dayMax = 5;
const left = dayMax - todayGivenCount;

const count = event.text?.match(/:waffle:/g)?.length ?? 0;
const targetUsers = ((event.text?.match(/<@[A-Z0-9]+>/g) ?? []) as Mention[]).filter(
(m) => m !== slackIDToMention(user),
);

if (count === 0 || targetUsers.length === 0) return;
const total = count * targetUsers.length;

const href = (
await messageRepository.getPermalink({
Expand All @@ -68,11 +81,33 @@ export const implementSlackEventService = ({
})
).link;

if (left < total) {
await messageRepository.sendMessage({
channel: event.user,
text: `*You have only ${left} ${left === 1 ? 'Waffle' : 'Waffles'} left for today!*`,
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*You have only ${left} ${left === 1 ? 'Waffle' : 'Waffles'} left for today!*`,
},
accessory: {
type: 'button',
text: { type: 'plain_text', text: 'View Message' },
url: href,
},
},
],
});
return;
}

await Promise.all([
...[
{
channel: event.user,
text: `*You Gave ${count} ${count === 1 ? 'Waffle' : 'Waffles'} to ${targetUsers.join(',')}!*`,
text: `*You Gave ${count} ${count === 1 ? 'Waffle' : 'Waffles'} to ${targetUsers.join(',')} (${left - total} left)*`,
},
...targetUsers.map((u) => ({
channel: mentionToSlackID(u),
Expand Down
24 changes: 24 additions & 0 deletions src/utils/getTodayStartAsKST.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { expect, test } from 'bun:test';

import { getTodayStartAsKST } from './getTodayStartAsKST';

test('getTodayStartAsKST', () => {
const initialTZ = process.env.TZ;

process.env.TZ = 'America/New_York';
const americaNewYorkDate = new Date('2024-01-28T15:20:46.000Z');
expect(americaNewYorkDate.getHours()).toEqual(10);
expect(getTodayStartAsKST(americaNewYorkDate)).toEqual(new Date('2024-01-28T15:00:00.000Z'));

process.env.TZ = 'Europe/London';
const europeLondonDate = new Date('2024-01-28T15:20:46.000Z');
expect(europeLondonDate.getHours()).toEqual(15);
expect(getTodayStartAsKST(europeLondonDate)).toEqual(new Date('2024-01-28T15:00:00.000Z'));

process.env.TZ = 'Asia/Seoul';
const asiaSeoulDate = new Date('2024-01-28T15:20:46.000Z');
expect(asiaSeoulDate.getHours()).toEqual(0);
expect(getTodayStartAsKST(asiaSeoulDate)).toEqual(new Date('2024-01-28T15:00:00.000Z'));

process.env.TZ = initialTZ;
});
9 changes: 9 additions & 0 deletions src/utils/getTodayStartAsKST.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const getTodayStartAsKST = (now: Date): Date => {
const currentOffset = now.getTimezoneOffset() / 60;

const offset = (-9 - currentOffset) * 60 * 60 * 1000;

const temp = new Date(now.getTime() - offset);
temp.setHours(0, 0, 0, 0);
return new Date(temp.getTime() + offset);
};

0 comments on commit b12010a

Please sign in to comment.