Skip to content

Commit 9c7d3a0

Browse files
committed
.
1 parent 54f1da9 commit 9c7d3a0

11 files changed

Lines changed: 174 additions & 88 deletions

File tree

astro.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { defineConfig } from 'astro/config';
44
// https://astro.build/config
55
export default defineConfig({
66
site: 'https://grassproject.github.io',
7+
output: 'server',
78
server: {
89
allowedHosts: ['0.tcp.jp.ngrok.io']
910
}

public/script/CookieManager.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export function getCookie(name) {
2+
const nameEQ = name + "=";
3+
const ca = document.cookie.split(';');
4+
for (let i = 0; i < ca.length; i++) {
5+
let c = ca[i].trim();
6+
if (c.indexOf(nameEQ) === 0) {
7+
return decodeURIComponent(c.substring(nameEQ.length, c.length));
8+
}
9+
}
10+
return null;
11+
}
12+
13+
export function setCookie(name, value) {
14+
const cookieValue = typeof value === 'object' ? JSON.stringify(value) : value;
15+
document.cookie = `${name}=${encodeURIComponent(cookieValue)};path=/`;
16+
}
17+
18+
export function removeCookie(name) {
19+
document.cookie = name + "=; Max-Age=0; path=/";
20+
}
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import qs from 'qs';
44
const clientId = '1358603949015564449';
55
const clientSecret = 's8Tf9GpGwOHxaDcqXaF8NnZzF_GEkduL';
66

7-
export async function getDiscordUser(code: string, redirectUri: string) {
7+
export async function getDiscordUser(code, redirectUri) {
88
try {
99
const tokenRes = await axios.post(
1010
'https://discord.com/api/v10/oauth2/token',
@@ -27,8 +27,10 @@ export async function getDiscordUser(code: string, redirectUri: string) {
2727
});
2828

2929
return userRes.data;
30-
} catch (err: any) {
30+
} catch (err) {
3131
console.error(err.response?.data || err.message);
3232
throw new Error(err.message || 'Discord API Error');
3333
}
34-
}
34+
}
35+
36+
module.exports = { getDiscordUser };

public/script/consts.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
const url= 'https://grassproject.github.io';
2+
export default url

src/components/BaseFooter.astro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
</div>
2020
&copy; 2025 GrassProject. ALL RIGHT RESERVED
2121
</footer>
22-
<style>
22+
<style is:global>
2323
.social-icons {
2424
display: flex;
2525
gap: 1rem;
@@ -38,6 +38,7 @@
3838
}
3939

4040
footer {
41+
text-align: center;
4142
margin-top: 2rem;
4243
color: #c9f1a4;
4344
padding: 1.2rem 0;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
import url from '../../../public/script/consts.ts'
3+
4+
const redirectUri = `${url}/callback`;
5+
---
6+
7+
8+
<div class="logging" id="login-container">
9+
<h1 id="logging-in" data-redirect-uri={redirectUri}>Logging in...</h1>
10+
</div>
11+
12+
<script type="module">
13+
function setCookie(name, value) {
14+
const cookieValue = typeof value === 'object' ? JSON.stringify(value) : value;
15+
document.cookie = `${name}=${encodeURIComponent(cookieValue)};path=/`;
16+
}
17+
18+
const h1 = document.getElementById("logging-in");
19+
const url = h1.dataset.redirectUri;
20+
const urlParams = new URLSearchParams(window.location.search);
21+
const code = urlParams.get('code') || 'NULL'
22+
const redirectUri = `${url}`;
23+
24+
if (!code || code === 'NULL') {
25+
alert('Code Not Received')
26+
} else {
27+
28+
const res = await fetch('/api/discord', {
29+
method: 'POST',
30+
headers: { 'Content-Type': 'application/json' },
31+
body: JSON.stringify({ code, redirectUri }),
32+
});
33+
34+
const user = await res.json();
35+
36+
if (user.error) {
37+
console.error('Discord user fetch failed:', user.error);
38+
alert('Failed to fetch Discord user info');
39+
} else {
40+
console.log(user);
41+
setCookie('user', {
42+
id: user.id,
43+
username: user.username,
44+
global_name: user.global_name,
45+
email: user.email,
46+
locale: user.locale,
47+
banner_color: user.banner_color
48+
});
49+
setCookie('isLoggedIn', 'true');
50+
51+
window.location.href = '/';
52+
}
53+
}
54+
</script>
55+
<style>
56+
.logging {
57+
text-align: center;
58+
margin-top: 12rem;
59+
margin-bottom: 6rem;
60+
}
61+
</style>

src/consts.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/layouts/Layout.astro

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
import BaseHeader from "../components/BaseHeader.astro";
33
import Navigator from "../components/Navigator.astro";
44
import BaseFooter from "../components/BaseFooter.astro";
5+
import url from "../../public/script/consts.ts";
6+
7+
const redirectUri = `${url}/callback`;
8+
const discordLoginUrl = `https://discord.com/oauth2/authorize?client_id=1358603949015564449&response_type=code&redirect_uri=${
9+
encodeURIComponent(redirectUri)
10+
}&scope=email+identify+openid`;
511
---
612

713
<html lang="ko">
@@ -15,25 +21,19 @@ import BaseFooter from "../components/BaseFooter.astro";
1521

1622
<Navigator/>
1723

18-
<div class="login" id="login-container"></div>
24+
<div class="login" id="login-container" data-discord-login-url={discordLoginUrl}></div>
1925

2026
<BaseFooter/>
2127
</div>
2228

23-
<script type="module">
24-
import Cookies from "js-cookie";
25-
import {url} from "../consts.ts";
2629

27-
const redirectUri = `${url}/callback`;
28-
const discordLoginUrl = `https://discord.com/oauth2/authorize?client_id=1358603949015564449&response_type=code&redirect_uri=${
29-
encodeURIComponent(redirectUri
30-
)}&scope=email+identify+openid`;
30+
<script type="module">
31+
import {getCookie, removeCookie} from "/script/CookieManager.js";
3132

3233
const container = document.getElementById("login-container");
33-
const storedUser = Cookies.get("user");
34-
const storedLoggedIn = Cookies.get("isLoggedIn");
35-
36-
// if (!container || !storedUser || !storedLoggedIn) return;
34+
const discordLoginUrl = container.dataset.discordLoginUrl;
35+
const storedUser = getCookie('user')
36+
const storedLoggedIn = getCookie('isLoggedIn')
3737

3838
if (storedUser && storedLoggedIn === "true") {
3939
const user = JSON.parse(storedUser);
@@ -43,26 +43,24 @@ import BaseFooter from "../components/BaseFooter.astro";
4343
<button id="logout-btn" class="round-btn logout-btn">
4444
<span class="btn-text">Logout</span>
4545
</button>
46-
</div>
47-
`;
46+
</div>`;
4847

4948
document.getElementById("logout-btn")?.addEventListener("click", () => {
50-
Cookies.remove("user");
51-
Cookies.remove("isLoggedIn");
49+
removeCookie('user');
50+
removeCookie('isLoggedIn')
5251
location.reload();
5352
});
5453
} else {
5554
container.innerHTML = `
5655
<a href="${discordLoginUrl}" class="round-btn login-btn">
5756
<span class="btn-text">Login</span>
58-
</a>
59-
`;
57+
</a>`;
6058
}
6159
</script>
6260
</body>
6361
</html>
6462

65-
<style>
63+
<style is:global>
6664
.container {
6765
min-height: 100vh;
6866
justify-content: space-between;
@@ -78,7 +76,7 @@ import BaseFooter from "../components/BaseFooter.astro";
7876

7977
.user-info {
8078
display: flex;
81-
flex-direction: column;
79+
flex-direction: row;
8280
align-items: center;
8381
gap: 0.5rem;
8482
}
@@ -88,7 +86,7 @@ import BaseFooter from "../components/BaseFooter.astro";
8886
transition: opacity 0.3s ease-in-out;
8987
}
9088

91-
.user-info:hover .user-text {
89+
.user-info:hover ~ .logout-btn {
9290
opacity: 0;
9391
}
9492

@@ -132,6 +130,5 @@ import BaseFooter from "../components/BaseFooter.astro";
132130

133131
.logout-btn {
134132
background: #c9f1a4;
135-
color: #242424;
136133
}
137134
</style>

src/pages/404.astro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
---
22
33
import Layout from "../layouts/Layout.astro";
4-
import NotFound from "../components/page/NotFound.astro";---
4+
import NotFound from "../components/page/NotFound.astro";
5+
---
56

67
<Layout>
78
<NotFound/>

src/pages/api/discord.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
export const prerender = false;
2+
3+
import axios from 'axios';
4+
import qs from 'qs';
5+
import type {APIRoute} from "astro";
6+
7+
const clientId = '1358603949015564449';
8+
const clientSecret = 's8Tf9GpGwOHxaDcqXaF8NnZzF_GEkduL';
9+
10+
export const POST: APIRoute = async ({ request }) => {
11+
let data;
12+
try {
13+
data = await request.json();
14+
} catch (err) {
15+
return new Response(JSON.stringify({ error: 'Invalid JSON' }), { status: 400 });
16+
}
17+
18+
const { code, redirectUri } = data;
19+
if (!code || !redirectUri) {
20+
return new Response(JSON.stringify({ error: 'Missing code or redirectUri' }), { status: 400 });
21+
}
22+
23+
try {
24+
// console.log(`redirect: ${redirectUri}`)
25+
const tokenRes = await axios.post(
26+
'https://discord.com/api/v10/oauth2/token',
27+
qs.stringify({
28+
grant_type: 'authorization_code',
29+
code,
30+
redirect_uri: redirectUri,
31+
scope: 'identify email openid',
32+
}),
33+
{
34+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
35+
auth: { username: clientId, password: clientSecret },
36+
}
37+
);
38+
39+
const accessToken = tokenRes.data.access_token;
40+
41+
const userRes = await axios.get('https://discord.com/api/v10/users/@me', {
42+
headers: { Authorization: `Bearer ${accessToken}` },
43+
});
44+
45+
return new Response(JSON.stringify(userRes.data), {
46+
status: 200,
47+
headers: { 'Content-Type': 'application/json' },
48+
});
49+
} catch (err: any) {
50+
console.error(err.response?.data || err.message);
51+
return new Response(
52+
JSON.stringify({ error: 'Discord API Error' }),
53+
{ status: 500 }
54+
);
55+
}
56+
};

0 commit comments

Comments
 (0)