-8
Dockerfile
-8
Dockerfile
···
3
3
ARG SOURCE_COMMIT
4
4
ARG VITE_BOT_API_URL
5
5
ARG VITE_STATUS_API_KEY
6
-
ARG VITE_FRONTEND_URL
7
-
ARG VITE_DISCORD_CLIENT_ID
8
6
ARG STATUS_API_KEY
9
7
10
8
ENV SOURCE_COMMIT=${SOURCE_COMMIT}
11
9
ENV NODE_ENV=production
12
10
ENV VITE_BOT_API_URL=${VITE_BOT_API_URL}
13
11
ENV VITE_STATUS_API_KEY=${VITE_STATUS_API_KEY}
14
-
ENV VITE_FRONTEND_URL=${VITE_FRONTEND_URL}
15
-
ENV VITE_DISCORD_CLIENT_ID=${VITE_DISCORD_CLIENT_ID}
16
12
ENV STATUS_API_KEY=${STATUS_API_KEY}
17
13
18
14
WORKDIR /app
···
52
48
ARG SOURCE_COMMIT
53
49
ARG VITE_BOT_API_URL
54
50
ARG VITE_STATUS_API_KEY
55
-
ARG VITE_FRONTEND_URL
56
-
ARG VITE_DISCORD_CLIENT_ID
57
51
58
52
ENV SOURCE_COMMIT=${SOURCE_COMMIT}
59
53
ENV NODE_ENV=production
60
54
ENV VITE_BOT_API_URL=${VITE_BOT_API_URL}
61
55
ENV STATUS_API_KEY=${STATUS_API_KEY}
62
56
ENV VITE_STATUS_API_KEY=${VITE_STATUS_API_KEY}
63
-
ENV VITE_FRONTEND_URL=${VITE_FRONTEND_URL}
64
-
ENV VITE_DISCORD_CLIENT_ID=${VITE_DISCORD_CLIENT_ID}
65
57
66
58
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* && \
67
59
groupadd -g 1001 nodejs && \
+2
-2
docker-compose.example.yml
+2
-2
docker-compose.example.yml
···
6
6
args:
7
7
- VITE_BOT_API_URL=${VITE_BOT_API_URL:-https://aethel.xyz}
8
8
- VITE_STATUS_API_KEY=${VITE_STATUS_API_KEY}
9
-
- VITE_FRONTEND_URL=${VITE_FRONTEND_URL:-https://aethel.xyz}
10
-
- VITE_DISCORD_CLIENT_ID=${VITE_DISCORD_CLIENT_ID}
11
9
- STATUS_API_KEY=${STATUS_API_KEY}
12
10
- SOURCE_COMMIT=${SOURCE_COMMIT:-development}
13
11
container_name: aethel-bot
···
18
16
NODE_ENV: production
19
17
TOKEN: ${TOKEN}
20
18
CLIENT_ID: ${CLIENT_ID}
19
+
CLIENT_SECRET: ${CLIENT_SECRET}
20
+
REDIRECT_URI: ${REDIRECT_URI}
21
21
DATABASE_URL: ${DATABASE_URL}
22
22
API_KEY_ENCRYPTION_SECRET: ${API_KEY_ENCRYPTION_SECRET}
23
23
STATUS_API_KEY: ${STATUS_API_KEY}
+6
-5
src/index.ts
+6
-5
src/index.ts
···
76
76
const bot = new BotClient();
77
77
bot.init();
78
78
79
+
app.use(async (req, res, next) => {
80
+
logger.info(`API [${req.method}] ${req.path}`); // log the api request
81
+
next();
82
+
})
83
+
79
84
app.use('/api/auth', authRoutes);
80
85
app.use('/api/todos', todosRoutes);
81
86
app.use('/api/user/api-keys', apiKeysRoutes);
···
87
92
res.status(200).json({ status: 'ok', timestamp: new Date().toISOString() });
88
93
});
89
94
90
-
app.use(e.static('web/dist'));
91
95
92
96
app.get('*', (req, res) => {
93
-
if (req.path.startsWith('/api/')) {
94
-
return res.status(404).json({ error: 'Not found' });
95
-
}
96
-
res.sendFile('index.html', { root: 'web/dist' });
97
+
return res.status(404).json({ status: 404, message: "Not Found" });
97
98
});
98
99
99
100
setInterval(
+6
-7
src/routes/auth.ts
+6
-7
src/routes/auth.ts
···
6
6
7
7
const router = Router();
8
8
9
-
const DISCORD_CLIENT_ID = process.env.DISCORD_CLIENT_ID;
10
-
const DISCORD_CLIENT_SECRET = process.env.DISCORD_CLIENT_SECRET;
11
-
const DISCORD_REDIRECT_URI =
12
-
process.env.DISCORD_REDIRECT_URI || 'http://localhost:8080/api/auth/discord/callback';
9
+
const DISCORD_CLIENT_ID = process.env.CLIENT_ID;
10
+
const DISCORD_CLIENT_SECRET = process.env.CLIENT_SECRET;
11
+
const DISCORD_REDIRECT_URI = process.env.REDIRECT_URI;
13
12
const JWT_SECRET = process.env.JWT_SECRET || 'your-jwt-secret';
14
-
const FRONTEND_URL = process.env.FRONTEND_URL || 'http://localhost:2020';
13
+
const FRONTEND_URL = process.env.FRONTEND_URL || 'http://localhost:3000';
15
14
16
15
interface DiscordUser {
17
16
id: string;
···
22
21
}
23
22
24
23
router.get('/discord', (req, res) => {
25
-
const discordAuthUrl = `https://discord.com/api/oauth2/authorize?client_id=${DISCORD_CLIENT_ID}&redirect_uri=${encodeURIComponent(DISCORD_REDIRECT_URI)}&response_type=code&scope=identify`;
24
+
const discordAuthUrl = `https://discord.com/api/oauth2/authorize?client_id=${DISCORD_CLIENT_ID}&redirect_uri=${encodeURIComponent(DISCORD_REDIRECT_URI!)}&response_type=code&scope=identify`;
26
25
res.redirect(discordAuthUrl);
27
26
});
28
27
···
50
49
client_secret: DISCORD_CLIENT_SECRET!,
51
50
grant_type: 'authorization_code',
52
51
code: code as string,
53
-
redirect_uri: DISCORD_REDIRECT_URI,
52
+
redirect_uri: DISCORD_REDIRECT_URI!,
54
53
}),
55
54
});
56
55
+2
-3
src/utils/logger.ts
+2
-3
src/utils/logger.ts
···
58
58
new winston.transports.Console({
59
59
format: winston.format.combine(
60
60
winston.format.colorize(),
61
-
winston.format.printf(({ timestamp, level, message, service, ...meta }) => {
62
-
const metaStr = Object.keys(meta).length ? JSON.stringify(meta, null, 2) : '';
63
-
return `${timestamp} [${service}] ${level}: ${message} ${metaStr}`;
61
+
winston.format.printf(({ timestamp, level, message, service, environment, version }) => {
62
+
return `${timestamp} [${service}] [${environment}] [${version}] ${level}: ${message}`;
64
63
}),
65
64
),
66
65
}),
+1
-1
web/src/lib/api.ts
+1
-1
web/src/lib/api.ts
+2
-2
web/src/pages/LoginPage.tsx
+2
-2
web/src/pages/LoginPage.tsx
···
28
28
29
29
const handleDiscordLogin = async () => {
30
30
try {
31
-
window.location.href = `${import.meta.env.VITE_FRONTEND_URL}/api/auth/discord`;
31
+
window.location.href = `/api/auth/discord`;
32
32
} catch (_error) {
33
33
toast.error('Failed to initiate Discord login');
34
34
}
···
66
66
67
67
<button
68
68
onClick={handleDiscordLogin}
69
-
className="w-full flex items-center justify-center px-8 py-3 border border-transparent rounded-full shadow-sm text-white bg-[#5865F2] hover:bg-[#4752c4] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#5865F2] transition-all transform hover:scale-105 font-bold shadow-lg hover:shadow-xl"
69
+
className="w-full flex items-center justify-center px-8 py-3 border border-transparent rounded-full shadow-sm text-white bg-[#5865F2] hover:bg-[#4752c4] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#5865F2] transition-all transform hover:scale-105 font-bold hover:shadow-xl"
70
70
>
71
71
<svg
72
72
className="w-5 h-5 mr-3"
+1
-1
web/src/stores/authStore.ts
+1
-1
web/src/stores/authStore.ts