Skip to content

Commit

Permalink
feat(traffic): traffic file deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
GZTimeWalker committed Apr 23, 2024
1 parent 6c1533e commit 8374f0d
Show file tree
Hide file tree
Showing 11 changed files with 306 additions and 92 deletions.
60 changes: 45 additions & 15 deletions src/GZCTF/ClientApp/src/Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3590,6 +3590,21 @@ export class Api<SecurityDataType extends unknown> extends HttpClient<SecurityDa
...params,
}),

/**
* @description 删除某队伍的流量包文件,需要Monitor权限
*
* @tags Game
* @name GameDeleteAllTeamTraffic
* @summary 删除某队伍的全部流量包文件
* @request DELETE:/api/game/captures/{challengeId}/{partId}/all
*/
gameDeleteAllTeamTraffic: (challengeId: number, partId: number, params: RequestParams = {}) =>
this.request<void, RequestResponse>({
path: `/api/game/captures/${challengeId}/${partId}/all`,
method: "DELETE",
...params,
}),

/**
* @description 删除,需要User权限
*
Expand All @@ -3605,6 +3620,21 @@ export class Api<SecurityDataType extends unknown> extends HttpClient<SecurityDa
...params,
}),

/**
* @description 删除流量包文件,需要Monitor权限
*
* @tags Game
* @name GameDeleteTeamTraffic
* @summary 删除流量包文件
* @request DELETE:/api/game/captures/{challengeId}/{partId}/{filename}
*/
gameDeleteTeamTraffic: (challengeId: number, partId: number, filename: string, params: RequestParams = {}) =>
this.request<void, RequestResponse>({
path: `/api/game/captures/${challengeId}/${partId}/${filename}`,
method: "DELETE",
...params,
}),

/**
* @description 获取比赛事件数据,需要Monitor权限
*
Expand Down Expand Up @@ -3796,6 +3826,21 @@ export class Api<SecurityDataType extends unknown> extends HttpClient<SecurityDa
mutateGameGamesAll: (data?: BasicGameInfoModel[] | Promise<BasicGameInfoModel[]>, options?: MutatorOptions) =>
mutate<BasicGameInfoModel[]>(`/api/game`, data, options),

/**
* @description 获取流量包文件,需要Monitor权限
*
* @tags Game
* @name GameGetAllTeamTraffic
* @summary 获取流量包文件压缩包
* @request GET:/api/game/captures/{challengeId}/{partId}/all
*/
gameGetAllTeamTraffic: (challengeId: number, partId: number, params: RequestParams = {}) =>
this.request<void, RequestResponse>({
path: `/api/game/captures/${challengeId}/${partId}/all`,
method: "GET",
...params,
}),

/**
* @description 获取比赛题目信息,需要User权限,需要当前激活队伍已经报名
*
Expand Down Expand Up @@ -3980,21 +4025,6 @@ export class Api<SecurityDataType extends unknown> extends HttpClient<SecurityDa
options?: MutatorOptions,
) => mutate<FileRecord[]>(`/api/game/captures/${challengeId}/${partId}`, data, options),

/**
* @description 获取流量包文件,需要Monitor权限
*
* @tags Game
* @name GameGetTeamTrafficZip
* @summary 获取流量包文件压缩包
* @request GET:/api/game/captures/{challengeId}/{partId}/all
*/
gameGetTeamTrafficZip: (challengeId: number, partId: number, params: RequestParams = {}) =>
this.request<void, RequestResponse>({
path: `/api/game/captures/${challengeId}/${partId}/all`,
method: "GET",
...params,
}),

/**
* @description 获取赛后题解提交情况,需要User权限
*
Expand Down
18 changes: 9 additions & 9 deletions src/GZCTF/ClientApp/src/components/ActionIconWithConfirm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ export const ActionIconWithConfirm: FC<ActionIconWithConfirmProps> = (props) =>
</Text>

<Group w="100%" position="apart">
<Button
size="xs"
py={2}
variant="outline"
disabled={props.disabled}
onClick={() => setOpened(false)}
>
{t('common.modal.cancel')}
</Button>
<Button
size="xs"
py={2}
Expand All @@ -71,15 +80,6 @@ export const ActionIconWithConfirm: FC<ActionIconWithConfirmProps> = (props) =>
>
{t('common.modal.confirm')}
</Button>
<Button
size="xs"
py={2}
variant="outline"
disabled={props.disabled}
onClick={() => setOpened(false)}
>
{t('common.modal.cancel')}
</Button>
</Group>
</Stack>
</Popover.Dropdown>
Expand Down
35 changes: 14 additions & 21 deletions src/GZCTF/ClientApp/src/components/ScrollSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ export type SelectableItemComponent<I = object> = FC<PropsWithItem<SelectableIte

interface ScrollSelectProps extends ScrollAreaProps {
itemComponent: React.FC<any>
itemComponentProps?: any
emptyPlaceholder?: React.ReactNode
items?: any[]
customClick?: boolean
selectedId?: number | null
onSelectId: (item: any | null) => void
onSelect?: (item: any | null) => void
}

const useItemStyle = createStyles((theme) => ({
Expand Down Expand Up @@ -76,37 +77,29 @@ export const SelectableItem = forwardRef<HTMLButtonElement, SelectableItemProps>
const ScrollSelect: FC<ScrollSelectProps> = (props) => {
const {
itemComponent: ItemComponent,
itemComponentProps,
emptyPlaceholder,
items,
selectedId,
onSelectId,
customClick,
onSelect,
...ScrollAreaProps
} = props

return (
<ScrollArea type="auto" {...ScrollAreaProps}>
<ScrollArea type="never" {...ScrollAreaProps}>
{!items || items.length === 0 ? (
<Center h="100%">{emptyPlaceholder}</Center>
) : (
<Stack spacing={2} w="100%">
{customClick
? items.map((item) => (
<ItemComponent
key={item.id}
onClick={() => onSelectId(item)}
active={false}
item={item}
/>
))
: items.map((item) => (
<ItemComponent
key={item.id}
onClick={() => onSelectId(item.id)}
active={selectedId === item.id}
item={item}
/>
))}
{items.map((item) => (
<ItemComponent
key={item.id}
onClick={onSelect && (() => onSelect(item.id))}
active={selectedId && selectedId === item.id}
item={item}
{...itemComponentProps}
/>
))}
</Stack>
)}
</ScrollArea>
Expand Down
71 changes: 51 additions & 20 deletions src/GZCTF/ClientApp/src/components/TrafficItems.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { Avatar, Badge, Group, rem, Stack, Text, useMantineTheme } from '@mantine/core'
import { mdiFileDownloadOutline, mdiMenuRight } from '@mdi/js'
import { mdiDeleteOutline, mdiFileDownloadOutline, mdiMenuRight } from '@mdi/js'
import { Icon } from '@mdi/react'
import dayjs from 'dayjs'
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { SelectableItem, SelectableItemComponent } from '@Components/ScrollSelect'
import {
PropsWithItem,
SelectableItem,
SelectableItemComponent,
SelectableItemProps,
} from '@Components/ScrollSelect'
import { useChallengeTagLabelMap, HunamizeSize } from '@Utils/Shared'
import {
ChallengeTag,
Expand All @@ -12,6 +18,7 @@ import {
FileRecord,
TeamTrafficModel,
} from '@Api'
import { ActionIconWithConfirm } from './ActionIconWithConfirm'

const itemHeight = rem(60)

Expand Down Expand Up @@ -85,28 +92,52 @@ export const TeamItem: SelectableItemComponent<TeamTrafficModel> = (itemProps) =
)
}

export const FileItem: SelectableItemComponent<FileRecord> = (itemProps) => {
const { item, ...props } = itemProps
export interface FileItemProps extends SelectableItemProps {
t: (key: string) => string
disabled: boolean
onDownload: (file: FileRecord) => void
onDelete: (file: FileRecord) => Promise<void>
}

export const FileItem: FC<PropsWithItem<FileItemProps, FileRecord>> = (itemProps) => {
const { item, onDownload, onDelete, disabled, t, ...props } = itemProps

return (
<SelectableItem h={itemHeight} {...props}>
<Group position="apart" spacing={0} w="100%" noWrap>
<Group position="left" spacing="sm" noWrap>
<Icon path={mdiFileDownloadOutline} size={1.2} />
<SelectableItem h={itemHeight} active={false} {...props}>
<Group position="apart" spacing={0} noWrap w="100%">
<Group
position="apart"
spacing={0}
noWrap
w="calc(100% - 2.5rem)"
onClick={() => onDownload(item)}
>
<Group position="left" spacing="sm" noWrap>
<Icon path={mdiFileDownloadOutline} size={1.2} />

<Stack spacing={0} align="flex-start">
<Text truncate fw={500} w="calc(50vw - 22rem)">
{item.fileName}
</Text>
<Badge size="sm" color="indigo">
{dayjs(item.updateTime).format('MM/DD HH:mm:ss')}
</Badge>
</Stack>
</Group>
<Stack spacing={0} align="flex-start">
<Text truncate fw={500}>
{item.fileName}
</Text>
<Badge size="sm" color="indigo">
{dayjs(item.updateTime).format('MM/DD HH:mm:ss')}
</Badge>
</Stack>
</Group>

<Text fw={500} size="sm">
{HunamizeSize(item.size ?? 0)}
</Text>
<Text fw={500} size="sm">
{HunamizeSize(item.size ?? 0)}
</Text>
</Group>
<Group position="right" spacing="sm" noWrap w="2.5rem">
<ActionIconWithConfirm
iconPath={mdiDeleteOutline}
color="red"
message={t('game.content.traffic.delete_confirm')}
disabled={disabled}
onClick={() => onDelete(item)}
/>
</Group>
</Group>
</SelectableItem>
)
Expand Down
10 changes: 10 additions & 0 deletions src/GZCTF/ClientApp/src/locales/en_US/game.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"button": {
"challenges": "Challenges",
"delete": {
"all_traffic": "Delete all listed traffic"
},
"download": {
"all_traffic": "Download all listed traffic",
"scoreboard": "Scoreboard",
Expand Down Expand Up @@ -83,6 +86,10 @@
},
"total_duration": "{{hours}}h in total",
"total_time": "Duration",
"traffic": {
"delete_confirm": "Delete this traffic file?",
"deleted_all_confirm": "Delete all listed traffic?"
},
"writeup": {
"current": "Current Writeup",
"deadline_exceeded": "Submission deadline has passed",
Expand Down Expand Up @@ -163,6 +170,9 @@
"not_started": "Game not yet started",
"select_chal_and_part": "Please select challenges and teams first",
"suspended": "You have been banned",
"traffic": {
"deleted": "Traffic file(s) has been deleted"
},
"writeup": {
"submitted": "Writeup was successfully submitted"
}
Expand Down
10 changes: 10 additions & 0 deletions src/GZCTF/ClientApp/src/locales/ja_JP/game.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"scoreboard": "ランキングをダウンロード",
"submissionsheet": "提出物をすべてダウンロード"
},
"delete": {
"all_traffic": "すべてのトラフィックを削除する"
},
"finished": "ゲーム終了",
"hide_solved": "解いたものを非表示にする",
"join": "ゲームに参加",
Expand Down Expand Up @@ -83,6 +86,10 @@
},
"total_duration": "合計 {{hours}} 時間",
"total_time": "期限",
"traffic": {
"delete_confirm": "このトラフィックファイルを削除しますか?",
"deleted_all_confirm": "すべてのトラフィックを削除しますか?"
},
"writeup": {
"current": "現在の提出物",
"deadline_exceeded": "提出期限が過ぎました",
Expand Down Expand Up @@ -163,6 +170,9 @@
"not_started": "ゲームはまだ開始されていません",
"select_chal_and_part": "まずチャレンジとチームを選んでください",
"suspended": "あなたの参加は禁止されています",
"traffic": {
"deleted": "トラフィックファイルは削除されました"
},
"writeup": {
"submitted": "記事が正常に提出されました"
}
Expand Down
10 changes: 10 additions & 0 deletions src/GZCTF/ClientApp/src/locales/zh_CN/game.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"scoreboard": "下载积分榜",
"submissionsheet": "下载全部提交"
},
"delete": {
"all_traffic": "删除全部列出流量"
},
"finished": "比赛结束",
"hide_solved": "隐藏已解出",
"join": "报名参赛",
Expand Down Expand Up @@ -80,6 +83,10 @@
},
"total_duration": "共 {{hours}} 小时",
"total_time": "持续时间",
"traffic": {
"delete_confirm": "确认删除此流量文件?",
"deleted_all_confirm": "确认删除全部列出流量?"
},
"writeup": {
"current": "当前提交",
"deadline_exceeded": "提交截止时间已过",
Expand Down Expand Up @@ -160,6 +167,9 @@
"not_started": "比赛尚未开始",
"select_chal_and_part": "请先选择题目和队伍",
"suspended": "您已被禁赛",
"traffic": {
"deleted": "流量文件已删除"
},
"writeup": {
"submitted": "Writeup 已成功提交"
}
Expand Down

0 comments on commit 8374f0d

Please sign in to comment.