Skip to content

Commit d22ef07

Browse files
committed
Improvements
1 parent 70c1237 commit d22ef07

File tree

7 files changed

+171
-26
lines changed

7 files changed

+171
-26
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ dist-ssr
2727

2828
package-lock.json
2929
localtest
30-
api/firebase.json
30+
31+
.VSCodeCounter

api/getuserinfo.js

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { refererCheck } from '../common/referer-check.js';
2+
3+
export default async (req, res) => {
4+
5+
// 限制只能从指定域名访问
6+
const referer = req.headers.referer;
7+
if (!refererCheck(referer)) {
8+
return res.status(403).json({ error: referer ? 'Access denied' : 'What are you doing?' });
9+
}
10+
11+
const key = process.env.IPCHECKING_API_KEY;
12+
13+
if (!key) {
14+
return res.status(500).json({ error: 'API key is missing' });
15+
}
16+
17+
// 构建请求
18+
const url = new URL(`https://api.ipcheck.ing/userinfo?key=${key}`);
19+
20+
try {
21+
const apiResponse = await fetch(url, {
22+
headers: {
23+
...req.headers,
24+
}
25+
});
26+
27+
if (!apiResponse.ok) {
28+
throw new Error(`API responded with status: ${apiResponse.status}`);
29+
}
30+
31+
const data = await apiResponse.json();
32+
res.json(data);
33+
} catch (error) {
34+
console.error("Error during API request:", error);
35+
res.status(500).json({ error: error.message });
36+
}
37+
}

backend-server.js

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import ipapiisHandler from './api/ipapiis.js';
1919
import invisibilitytestHandler from './api/invisibilitytest.js';
2020
import macChecker from './api/macchecker.js';
2121
import maxmindHandler from './api/maxmind.js';
22+
import getuserinfo from './api/getuserinfo.js';
2223

2324
dotenv.config();
2425

@@ -139,6 +140,7 @@ app.get('/api/ipapiis', ipapiisHandler);
139140
app.get('/api/invisibility', invisibilitytestHandler);
140141
app.get('/api/macchecker', macChecker);
141142
app.get('/api/maxmind', maxmindHandler);
143+
app.get('/api/getuserinfo', getuserinfo);
142144

143145
// 使用查询参数处理所有配置请求
144146
app.get('/api/configs', validateConfigs);

frontend/components/Nav.vue

+73-16
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@
5858
<div class="dropdown">
5959
<button class="btn dropdown-toggle d-flex align-items-center flex-row "
6060
:class="{ 'btn-outline-light': isDarkMode, 'btn-dark': !isDarkMode }" type="button"
61-
data-bs-toggle="dropdown" :data-bs-theme="isDarkMode ? 'dark' : ''" aria-expanded="false">
61+
data-bs-toggle="dropdown" :data-bs-theme="isDarkMode ? 'dark' : ''" aria-expanded="false"
62+
@click="getUserInfo">
6263
<span v-if="!store.user">
6364
{{ t('user.SignIn') }}
6465
</span>
@@ -70,18 +71,39 @@
7071
</span>
7172
</button>
7273
<ul class="dropdown-menu dropdown-menu-end" :data-bs-theme="isDarkMode ? 'dark' : ''">
74+
<li v-if="store.user" class="dropdown-header d-flex flex-column">
75+
<span>{{ t('user.Fields.User') }} : {{store.user.displayName}}</span>
76+
<span>{{ t('user.Fields.CreatedAt') }} : {{ unixToDateTime(store.user.metadata.createdAt) }}</span>
77+
<span>{{ t('user.Fields.Level') }} :&nbsp;
78+
<span v-if="userInfoFetched">{{ t('user.Level.' + userInfo.userLevel)}}</span>
79+
<span v-else>{{ t('user.Fields.Fetching') }}</span>
80+
</span>
81+
<span>{{ t('user.Fields.FunctionUses') }} :&nbsp;
82+
<span v-if="userInfoFetched">{{ userInfo.functionUses.total }}
83+
{{ t('user.Fields.Times') }}
84+
</span>
85+
<span v-else>{{ t('user.Fields.Fetching') }}</span>
86+
</span>
87+
</li>
88+
<li v-if="store.user">
89+
<hr class="dropdown-divider" />
90+
</li>
7391
<li v-if="!store.user"><a type="button" class="dropdown-item" @click="store.signInWithGoogle"><i
7492
class="bi bi-google"></i> {{ t('user.SignInWithGoogle') }}</a></li>
7593
<li v-if="!store.user"><a type="button" class="dropdown-item" @click="store.signInWithGithub"><i
7694
class="bi bi-github"></i> {{ t('user.SignInWithGithub') }}</a></li>
77-
<li v-if="store.user"><a type="button" class="dropdown-item" @click="store.signOut"><i
78-
class="bi bi-box-arrow-right"></i> {{ t('user.SignOut')
79-
}}</a></li>
80-
<li>
95+
<li v-if="!store.user">
8196
<hr class="dropdown-divider" />
8297
</li>
8398
<li><a type="button" class="dropdown-item" @click="openUserBenefits"><i class="bi bi-award-fill"></i> {{
8499
t('user.Benefits.Title') }}</a></li>
100+
<li v-if="store.user">
101+
<hr class="dropdown-divider" />
102+
</li>
103+
<li v-if="store.user"><a type="button" class="dropdown-item" @click="store.signOut"><i
104+
class="bi bi-box-arrow-right"></i> {{ t('user.SignOut')
105+
}}</a>
106+
</li>
85107
</ul>
86108
</div>
87109
</div>
@@ -142,6 +164,7 @@ import { useMainStore } from '@/store';
142164
import { useI18n } from 'vue-i18n';
143165
import { trackEvent } from '@/utils/use-analytics';
144166
import { Offcanvas, Modal } from 'bootstrap';
167+
import { authenticatedFetch } from '@/utils/authenticated-fetch';
145168
146169
const { t } = useI18n();
147170
@@ -157,6 +180,9 @@ const loaded = ref(false);
157180
const currentSection = computed(() => store.currentSection);
158181
const isFireBaseSet = computed(() => store.isFireBaseSet);
159182
183+
const userInfo = ref({});
184+
const userInfoFetched = ref(false);
185+
160186
// 打开偏好设置
161187
const OpenPreferences = () => {
162188
const offcanvasElement = document.getElementById('offcanvasPreferences');
@@ -170,17 +196,6 @@ const OpenPreferences = () => {
170196
trackEvent('Nav', 'NavClick', 'Preferences');
171197
};
172198
173-
// 打开 Modal
174-
const openUserBenefits = () => {
175-
const modalElement = document.getElementById('Benefits');
176-
const modalInstance = Modal.getOrCreateInstance(modalElement);
177-
if (modalInstance) {
178-
modalInstance.show();
179-
}
180-
181-
trackEvent('Nav', 'NavClick', 'UserBenefits');
182-
};
183-
184199
// 点击 Logo 事件处理
185200
const handleLogoClick = () => {
186201
if (window.scrollY === 0) {
@@ -197,6 +212,48 @@ const scrollToSection = (el, offset = 70) => {
197212
window.scrollTo({ top: y, behavior: "smooth" });
198213
}
199214
215+
// 转换 Unix 时间
216+
const unixToDateTime = (timestamp) => {
217+
timestamp = Number(timestamp);
218+
const options = {
219+
year: 'numeric',
220+
month: 'long',
221+
day: 'numeric',
222+
};
223+
const date = new Date(timestamp);
224+
return date.toLocaleString(undefined, options);
225+
}
226+
227+
// 打开 Modal
228+
const openUserBenefits = () => {
229+
const modalElement = document.getElementById('Benefits');
230+
const modalInstance = Modal.getOrCreateInstance(modalElement);
231+
if (modalInstance) {
232+
modalInstance.show();
233+
}
234+
235+
trackEvent('Nav', 'NavClick', 'UserBenefits');
236+
};
237+
238+
// 获取用户统计信息
239+
const getUserInfo = async () => {
240+
if (userInfoFetched.value) {
241+
return;
242+
}
243+
if (!store.user) {
244+
return;
245+
}
246+
try {
247+
const response = await authenticatedFetch(`/api/getuserinfo`);
248+
const data = response;
249+
userInfo.value = data;
250+
} catch (error) {
251+
console.error('Error fetching user info:', error);
252+
}
253+
254+
userInfoFetched.value = true;
255+
};
256+
200257
watch(() => store.allHasLoaded, (newValue) => {
201258
loaded.value = newValue;
202259
});

frontend/locales/en.json

+25-9
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,32 @@
77
"SignInToView": "Sign In to View",
88
"SignInToUse": "Please sign in to use",
99
"InvalidUserToken": "Invalid User Token",
10+
"Fields": {
11+
"User": "User",
12+
"CreatedAt": "Created At",
13+
"LastLogin": "Last Login",
14+
"Level": "User Level",
15+
"FunctionUses": "Advanced Usage",
16+
"Times": "Times",
17+
"Fetching": "Fetching..."
18+
},
19+
"Level": {
20+
"Standard": "Standard User",
21+
"Premium": "Premium User",
22+
"Owner": "Administrator",
23+
"Developer": "Developer",
24+
"HonoraryMember": "Honorary Member"
25+
},
1026
"Benefits": {
11-
"Title": "User Benefits",
12-
"Benefit": "Benefit",
13-
"Note1": "As an open-source product, your use of IPCheck.ing is free of charge.",
14-
"Note2": "However, to prevent abuse, we limit some features. By logging in, you will receive the following benefits:",
15-
"Benifit1": "When you use IPCheck.ing as IP data source, all fields are displayed in full.",
16-
"Benifit2": "You can use the invisibility test.",
17-
"Benifit3": "Reduces access restrictions on some features.",
18-
"FootNote": "More benefits are being developed..."
19-
}
27+
"Title": "User Benefits",
28+
"Benefit": "Benefit",
29+
"Note1": "As an open-source product, your use of IPCheck.ing is free of charge.",
30+
"Note2": "However, to prevent abuse, we limit some features. By logging in, you will receive the following benefits:",
31+
"Benifit1": "When you use IPCheck.ing as IP data source, all fields are displayed in full.",
32+
"Benifit2": "You can use the invisibility test.",
33+
"Benifit3": "Reduces access restrictions on some features.",
34+
"FootNote": "More benefits are being developed..."
35+
}
2036
},
2137
"nav": {
2238
"id": "nav",

frontend/locales/fr.json

+16
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,22 @@
77
"SignInToView": "Connectez-vous pour voir",
88
"SignInToUse": "Connectez-vous pour utiliser",
99
"InvalidUserToken": "Token utilisateur non valide",
10+
"Fields": {
11+
"User": "Utilisateur",
12+
"CreatedAt": "Créé Le",
13+
"LastLogin": "Dernière Connexion",
14+
"Level": "Niveau d'Utilisateur",
15+
"FunctionUses": "Utilisation des Avancées",
16+
"Times": "Fois",
17+
"Fetching": "Recherche..."
18+
},
19+
"Level": {
20+
"Standard": "Utilisateur Standard",
21+
"Premium": "Utilisateur Premium",
22+
"Owner": "Administrateur",
23+
"Developer": "Développeur",
24+
"HonoraryMember": "Membre Honoraire"
25+
},
1026
"Benefits": {
1127
"Title": "Avantages Utilisateurs",
1228
"Benefit": "Avantage",

frontend/locales/zh.json

+16
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,22 @@
77
"SignInToView": "登录后查看",
88
"SignInToUse": "请登录后使用",
99
"InvalidUserToken": "无效的用户 Token",
10+
"Fields": {
11+
"User": "用户",
12+
"CreatedAt": "创建于",
13+
"LastLogin": "最后登录",
14+
"Level": "用户等级",
15+
"FunctionUses": "高级功能使用",
16+
"Times": "",
17+
"Fetching": "获取中..."
18+
},
19+
"Level": {
20+
"Standard": "标准用户",
21+
"Premium": "高级用户",
22+
"Owner": "管理员",
23+
"Developer": "开发者",
24+
"HonoraryMember": "荣誉用户"
25+
},
1026
"Benefits": {
1127
"Title": "用户权益",
1228
"Benefit": "权益",

0 commit comments

Comments
 (0)