Skip to content

Commit

Permalink
feat(flat-pages): add sensitive page (#1902)
Browse files Browse the repository at this point in the history
  • Loading branch information
hyrious authored Apr 26, 2023
1 parent 830d551 commit 96ca7ae
Show file tree
Hide file tree
Showing 8 changed files with 352 additions and 3 deletions.
7 changes: 7 additions & 0 deletions desktop/renderer-app/src/route-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { ReplayPage } from "@netless/flat-pages/src/ReplayPage";
import SplashPage from "./pages/SplashPage";
import { ApplicationsPage } from "@netless/flat-pages/src/UserSettingPage/ApplicationsPage";
import { OAuthPage } from "@netless/flat-pages/src/UserSettingPage/OAuthPage";
import { SensitivePage } from "@netless/flat-pages/src/SensitivePage";
import { RoomType } from "@netless/flat-server-api";

export enum RouteNameType {
Expand All @@ -48,6 +49,7 @@ export enum RouteNameType {
DevicesTestPage = "DevicesTestPage",
ApplicationsPage = "ApplicationsPage",
OAuthPage = "OAuthPage",
SensitivePage = "SensitivePage",
}

export type ClassRouteName =
Expand Down Expand Up @@ -171,6 +173,11 @@ export const routeConfig = {
path: "/apps/",
component: OAuthPage,
},
[RouteNameType.SensitivePage]: {
title: "SensitivePage",
path: "/sensitive/",
component: SensitivePage,
},
} as const;

export type ExtraRouteConfig = {
Expand Down
44 changes: 43 additions & 1 deletion packages/flat-i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@
"title-DevicesTestPage": "Device Test",
"title-ApplicationsPage": "Applications",
"title-OAuthPage": "OAuth Applications",
"title-SensitivePage": "User Sensitive Information",
"inserting-courseware-tips": "Inserting courseware...",
"cancel-upload": "Cancel upload",
"cancel-upload-tips": "The upload has not been completed. Are you sure to cancel all ongoing uploads?",
Expand Down Expand Up @@ -609,5 +610,46 @@
"censorship-failed": "Your request had been denied because of legal reasons",
"oauth-uuid-not-found": "OAuth UUID not found",
"oauth-client-id-not-found": "OAuth client id not found",
"oauth-secret-uuid-not-found": "OAuth secret not found"
"oauth-secret-uuid-not-found": "OAuth secret not found",
"sensitive": {
"no-data": "No data",
"name": {
"column": "Type",
"avatar": "avatar",
"phone": "phone number",
"name": "nickname",
"wechat_name": "wechat nickname",
"cloud_storage": "cloud storage",
"recording": "recording"
},
"purpose": {
"column": "Purpose",
"avatar": "used to display avatar",
"phone": "used to register and send SMS",
"name": "used to change nickname",
"wechat_name": "used to register and bind wechat",
"cloud_storage": "used to store files",
"recording": "used to record and replay the session"
},
"description": {
"column": "Description",
"avatar": "When you upload an avatar.",
"phone": "When you register.",
"name": "When you change your nickname.",
"wechat_name": "When you register and bind wechat.",
"cloud_storage": "When you upload files.",
"recording": "When you record and replay the session."
},
"count": {
"column": "Count"
},
"content": {
"column": "Content"
}
},
"sensitive-range": {
"week": "Last Week",
"month": "Last Month",
"year": "Last Year"
}
}
44 changes: 43 additions & 1 deletion packages/flat-i18n/locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@
"title-DevicesTestPage": "设备检测",
"title-ApplicationsPage": "应用管理",
"title-OAuthPage": "OAuth 应用",
"title-SensitivePage": "用户使用信息",
"in-the-process-of-transcoding-tips": "正在转码中,请稍后再试",
"inserting-courseware-tips": "正在插入课件……",
"unable-to-insert-courseware": "无法插入课件",
Expand Down Expand Up @@ -609,5 +610,46 @@
"censorship-failed": "审核失败",
"oauth-uuid-not-found": "未找到该 OAuth App",
"oauth-client-id-not-found": "未找到该 OAuth App client",
"oauth-secret-uuid-not-found": "未找到该 OAuth 密钥"
"oauth-secret-uuid-not-found": "未找到该 OAuth 密钥",
"sensitive": {
"no-data": "未收集",
"name": {
"column": "信息名称",
"avatar": "头像",
"phone": "手机号码",
"name": "昵称",
"wechat_name": "微信昵称",
"cloud_storage": "云盘",
"recording": "房间录制"
},
"purpose": {
"column": "使用目的",
"avatar": "用于头像展示",
"phone": "账号注册与登录;发送短信通知",
"name": "用于昵称展示",
"wechat_name": "用于完成微信注册、绑定",
"cloud_storage": "用于存储和展示用户上传的文件",
"recording": "用于存储和回放房间内用户输入的内容"
},
"description": {
"column": "使用场景",
"avatar": "用户更换头像时",
"phone": "首次注册、登录时;发送短信通知时",
"name": "用户修改昵称时",
"wechat_name": "使用微信注册时;绑定微信时",
"cloud_storage": "用户上传文件时;房间内展示文件时",
"recording": "用户开启录制功能时;回放房间内容时"
},
"count": {
"column": "收集情况"
},
"content": {
"column": "信息内容"
}
},
"sensitive-range": {
"week": "最近七天",
"month": "最近一月",
"year": "最近一年"
}
}
4 changes: 4 additions & 0 deletions packages/flat-pages/src/AppRoutes/route-pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,8 @@ export const routePages: RoutePages = {
hasHeader: true,
component: () => import("../UserSettingPage/OAuthPage"),
},
[RouteNameType.SensitivePage]: {
title: "SensitivePage",
component: () => import("../SensitivePage"),
},
};
180 changes: 180 additions & 0 deletions packages/flat-pages/src/SensitivePage/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import "./style.less";

import React, { useCallback, useContext, useEffect, useMemo, useState } from "react";
import { observer } from "mobx-react-lite";
import { useSearchParam } from "react-use";
import { Redirect } from "react-router-dom";

import type { ColumnsType } from "antd/lib/table";
import { subWeeks, subMonths, subYears } from "date-fns";
import { Select, Table } from "antd";

import { useSafePromise } from "flat-components";
import { FlatI18n, useTranslate } from "@netless/flat-i18n";
import { SensitiveType, listSensitive } from "@netless/flat-server-api";
import { GlobalStoreContext } from "../components/StoreProvider";
import { NEED_BINDING_PHONE } from "../constants/config";

export type SensitiveRange = "1 week" | "1 month" | "1 year";

export interface SensitiveData {
type: SensitiveType;
name: string;
purpose: string;
description: string;
count: number;
content: string;
}

const SensitiveTypes: SensitiveType[] = [
SensitiveType.Avatar,
SensitiveType.Phone,
SensitiveType.Name,
SensitiveType.WeChatName,
SensitiveType.CloudStorage,
SensitiveType.Recording,
];

const BlankSensitiveTypes: SensitiveType[] = [SensitiveType.CloudStorage, SensitiveType.Recording];

export const SensitivePage = observer(function SensitivePage() {
const t = useTranslate();
const sp = useSafePromise();
const globalStore = useContext(GlobalStoreContext);
const token = useSearchParam("token") || globalStore.userInfo?.token;

const defaultSensitiveData = useCallback(
() =>
SensitiveTypes.map(type => ({
type,
name: t("sensitive.name." + type),
purpose: t("sensitive.purpose." + type),
description: t("sensitive.description." + type),
count: BlankSensitiveTypes.includes(type) ? -1 : 0,
content: "",
})),
[t],
);

const [range, setRange] = useState<SensitiveRange>("1 week");
const [data, setData] = useState<SensitiveData[]>([]);
const [loading, setLoading] = useState(false);

useEffect(() => {
if (NEED_BINDING_PHONE) {
FlatI18n.changeLanguage("zh-CN");
}
}, []);

useEffect(() => {
let from = new Date();
if (range === "1 week") {
from = subWeeks(from, 1);
} else if (range === "1 month") {
from = subMonths(from, 1);
} else if (range === "1 year") {
from = subYears(from, 1);
}

setLoading(true);
sp(listSensitive({ from, to: new Date() }))
.then(data => {
const newData = data.reduce((acc, cur) => {
const index = acc.findIndex(e => e.type === cur.type);
if (index !== -1) {
acc[index].count += 1;
acc[index].content = reduceContent(
cur.type,
acc[index].content,
cur.content,
);
}
return acc;
}, defaultSensitiveData());
if (NEED_BINDING_PHONE) {
const phoneIndex = newData.findIndex(e => e.type === SensitiveType.Phone);
if (phoneIndex !== -1) {
newData[phoneIndex].count = Math.max(newData[phoneIndex].count, 1);
}
}
setData(newData);
})
.finally(() => {
setLoading(false);
});
}, [defaultSensitiveData, range, sp, t]);

const columns = useMemo<ColumnsType<SensitiveData>>(
() => [
{
title: t("sensitive.name.column"),
dataIndex: "name",
align: "center",
},
{
title: t("sensitive.purpose.column"),
dataIndex: "purpose",
},
{
title: t("sensitive.description.column"),
dataIndex: "description",
},
{
title: t("sensitive.count.column"),
dataIndex: "count",
align: "center",
render: (count: number) =>
count < 0 ? "" : count === 0 ? t("sensitive.no-data") : String(count),
},
{
title: t("sensitive.content.column"),
dataIndex: "content",
align: "center",
},
],
[t],
);

if (!token) {
return <Redirect to="/login" />;
}

return (
<div className="sensitive-page-container">
<div className="sensitive-page">
<div className="sensitive-page-actions">
<Select loading={loading} value={range} onChange={setRange}>
<Select.Option key="1 week" value="1 week">
{t("sensitive-range.week")}
</Select.Option>
<Select.Option key="1 month" value="1 month">
{t("sensitive-range.month")}
</Select.Option>
<Select.Option key="1 year" value="1 year">
{t("sensitive-range.year")}
</Select.Option>
</Select>
</div>
<Table
className="sensitive-page-table"
columns={columns}
dataSource={data}
loading={loading}
locale={{ emptyText: t("no-data") }}
pagination={false}
rowKey="type"
/>
</div>
</div>
);
});

export default SensitivePage;

function reduceContent(type: SensitiveType, _content: string, input: string): string {
if (type === SensitiveType.Avatar) {
return "/";
}
// otherwise always return the last one
return input;
}
23 changes: 23 additions & 0 deletions packages/flat-pages/src/SensitivePage/style.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.sensitive-page-container {
background-color: #edf0f6;
padding: 8px 0;
}

.sensitive-page {
background-color: #fff;
padding: 16px;
margin-bottom: 8px;
}

.sensitive-page-actions {
text-align: right;
padding-bottom: 12px;

.ant-select {
text-align: left;
}
}

.sensitive-page-subtitle {
text-align: center;
}
4 changes: 4 additions & 0 deletions packages/flat-pages/src/route-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export enum RouteNameType {
DevicesTestPage = "DevicesTestPage",
ApplicationsPage = "ApplicationsPage",
OAuthPage = "OAuthPage",
SensitivePage = "SensitivePage",
}

export const routeConfig = {
Expand Down Expand Up @@ -90,6 +91,9 @@ export const routeConfig = {
[RouteNameType.OAuthPage]: {
path: "/apps/",
},
[RouteNameType.SensitivePage]: {
path: "/sensitive/",
},
} as const;

export type ExtraRouteConfig = {};
Expand Down
Loading

0 comments on commit 96ca7ae

Please sign in to comment.