diff --git a/api/migrations/54-ctf-by-date.sql b/api/migrations/54-ctf-by-date.sql new file mode 100644 index 000000000..5f36fffca --- /dev/null +++ b/api/migrations/54-ctf-by-date.sql @@ -0,0 +1,16 @@ +CREATE FUNCTION ctfnote.ctfs_by_date(year int, month int) + RETURNS SETOF ctfnote.ctf + AS $$ + SELECT + ctf.* + FROM + ctfnote.ctf + WHERE(start_time <= make_date(year, month, 1) + interval '1 month' + AND end_time >= make_date(year, month, 1)) + ORDER BY start_time; +$$ +LANGUAGE SQL +STABLE; + +GRANT EXECUTE ON FUNCTION ctfnote.ctfs_by_date(int, int) TO user_guest; + diff --git a/api/migrations/54-add-discord-integration-enabled.sql b/api/migrations/56-add-discord-integration-enabled.sql similarity index 98% rename from api/migrations/54-add-discord-integration-enabled.sql rename to api/migrations/56-add-discord-integration-enabled.sql index e94c5db8d..bfa1bd55c 100644 --- a/api/migrations/54-add-discord-integration-enabled.sql +++ b/api/migrations/56-add-discord-integration-enabled.sql @@ -1,8 +1,8 @@ -ALTER TABLE ctfnote.settings - ADD COLUMN "discord_integration_enabled" boolean NOT NULL DEFAULT FALSE; - -GRANT SELECT ("discord_integration_enabled") ON ctfnote.settings TO user_anonymous; -REVOKE UPDATE ON ctfnote.settings FROM user_admin; -GRANT UPDATE (unique_id, registration_allowed, registration_password_allowed, registration_password, registration_default_role, style, ical_password) ON ctfnote.settings TO user_admin; -GRANT UPDATE ("discord_integration_enabled") ON ctfnote.settings TO user_postgraphile; - +ALTER TABLE ctfnote.settings + ADD COLUMN "discord_integration_enabled" boolean NOT NULL DEFAULT FALSE; + +GRANT SELECT ("discord_integration_enabled") ON ctfnote.settings TO user_anonymous; +REVOKE UPDATE ON ctfnote.settings FROM user_admin; +GRANT UPDATE (unique_id, registration_allowed, registration_password_allowed, registration_password, registration_default_role, style, ical_password) ON ctfnote.settings TO user_admin; +GRANT UPDATE ("discord_integration_enabled") ON ctfnote.settings TO user_postgraphile; + diff --git a/api/src/plugins/importCtf.ts b/api/src/plugins/importCtf.ts index ed66ec5ca..56792a4fe 100644 --- a/api/src/plugins/importCtf.ts +++ b/api/src/plugins/importCtf.ts @@ -13,12 +13,23 @@ interface CTFTimeResponse { finish: string; } -async function fetchFromCtftime(id: number): Promise { +function fetchFromCtftime(id: number) { const url = `https://ctftime.org/api/v1/events/${id}/`; - const response = await axios.get(url, { - headers: { "User-Agent": "CTFNote" }, // The default axios user-agent is blacklisted by ctftime :/ - }); - return response.data; + return axios + .get(url, { + headers: { "User-Agent": "CTFNote" }, // The default axios user-agent is blacklisted by ctftime :/ + }) + .then((r) => ({ + title: r.data.title, + weight: r.data.weight, + url: r.data.url, + logo: r.data.logo, + ctftimeUrl: r.data.ctftime_url, + description: r.data.description, + start: r.data.start, + finish: r.data.finish, + })) + .catch(() => null); } export default makeExtendSchemaPlugin((build) => { @@ -34,11 +45,35 @@ export default makeExtendSchemaPlugin((build) => { query: Query } + type CtftimeCtf { + title: String! + weight: Float! + url: String! + logo: String! + ctftimeUrl: String! + description: String! + start: String! + finish: String! + } + extend type Mutation { importCtf(input: ImportCtfInput): ImportCtfPayload } + + extend type Query { + ctftimeCtfById(id: Int!): CtftimeCtf + } `, resolvers: { + Query: { + async ctftimeCtfById(_query, { id }, { pgRole }) { + if (pgRole !== "user_manager" && pgRole !== "user_admin") { + throw new Error("Permission denied"); + } + + return fetchFromCtftime(id); + }, + }, Mutation: { importCtf: async ( _query, @@ -47,6 +82,12 @@ export default makeExtendSchemaPlugin((build) => { resolveInfo ) => { const ctf = await fetchFromCtftime(ctftimeId); + if (!ctf) { + return { + data: null, + query: build.$$isQuery, + }; + } await savepointWrapper(pgClient, async () => { const { rows: [newCtf], @@ -68,7 +109,7 @@ export default makeExtendSchemaPlugin((build) => { ctf.weight, ctf.url, ctf.logo, - ctf.ctftime_url, + ctf.ctftimeUrl, ctf.description, ctf.start, ctf.finish, diff --git a/front/.yarn/cache/@babel-runtime-npm-7.24.4-1a974e2dd0-8ec8ce2c14.zip b/front/.yarn/cache/@babel-runtime-npm-7.24.4-1a974e2dd0-8ec8ce2c14.zip new file mode 100644 index 000000000..986750a12 Binary files /dev/null and b/front/.yarn/cache/@babel-runtime-npm-7.24.4-1a974e2dd0-8ec8ce2c14.zip differ diff --git a/front/.yarn/cache/@popperjs-core-npm-2.11.8-f1692e11a0-ddd16090cd.zip b/front/.yarn/cache/@popperjs-core-npm-2.11.8-f1692e11a0-ddd16090cd.zip new file mode 100644 index 000000000..025c268db Binary files /dev/null and b/front/.yarn/cache/@popperjs-core-npm-2.11.8-f1692e11a0-ddd16090cd.zip differ diff --git a/front/.yarn/cache/@types-lodash-npm-4.17.0-11e757616b-2053203292.zip b/front/.yarn/cache/@types-lodash-npm-4.17.0-11e757616b-2053203292.zip new file mode 100644 index 000000000..bcc3eaaf4 Binary files /dev/null and b/front/.yarn/cache/@types-lodash-npm-4.17.0-11e757616b-2053203292.zip differ diff --git a/front/.yarn/cache/@types-resize-observer-browser-npm-0.1.11-d331ee15e7-1e36bde885.zip b/front/.yarn/cache/@types-resize-observer-browser-npm-0.1.11-d331ee15e7-1e36bde885.zip new file mode 100644 index 000000000..4f009c0cb Binary files /dev/null and b/front/.yarn/cache/@types-resize-observer-browser-npm-0.1.11-d331ee15e7-1e36bde885.zip differ diff --git a/front/.yarn/cache/@types-web-bluetooth-npm-0.0.20-b0f3bdd4e5-2faa323e5c.zip b/front/.yarn/cache/@types-web-bluetooth-npm-0.0.20-b0f3bdd4e5-2faa323e5c.zip new file mode 100644 index 000000000..f92c81b09 Binary files /dev/null and b/front/.yarn/cache/@types-web-bluetooth-npm-0.0.20-b0f3bdd4e5-2faa323e5c.zip differ diff --git a/front/.yarn/cache/@vueuse-core-npm-11.0.1-e52000a502-c512c03cb8.zip b/front/.yarn/cache/@vueuse-core-npm-11.0.1-e52000a502-c512c03cb8.zip new file mode 100644 index 000000000..6f53d5744 Binary files /dev/null and b/front/.yarn/cache/@vueuse-core-npm-11.0.1-e52000a502-c512c03cb8.zip differ diff --git a/front/.yarn/cache/@vueuse-metadata-npm-11.0.1-e17636cd0b-ed1c617a2e.zip b/front/.yarn/cache/@vueuse-metadata-npm-11.0.1-e17636cd0b-ed1c617a2e.zip new file mode 100644 index 000000000..0a049b57d Binary files /dev/null and b/front/.yarn/cache/@vueuse-metadata-npm-11.0.1-e17636cd0b-ed1c617a2e.zip differ diff --git a/front/.yarn/cache/@vueuse-shared-npm-11.0.1-1874669b38-2800cad5c1.zip b/front/.yarn/cache/@vueuse-shared-npm-11.0.1-1874669b38-2800cad5c1.zip new file mode 100644 index 000000000..e29fdb8b8 Binary files /dev/null and b/front/.yarn/cache/@vueuse-shared-npm-11.0.1-1874669b38-2800cad5c1.zip differ diff --git a/front/.yarn/cache/braces-npm-3.0.2-782240b28a-966b1fb48d.zip b/front/.yarn/cache/braces-npm-3.0.2-782240b28a-966b1fb48d.zip new file mode 100644 index 000000000..4cf997e3b Binary files /dev/null and b/front/.yarn/cache/braces-npm-3.0.2-782240b28a-966b1fb48d.zip differ diff --git a/front/.yarn/cache/braces-npm-3.0.3-582c14023c-fad11a0d46.zip b/front/.yarn/cache/braces-npm-3.0.3-582c14023c-fad11a0d46.zip deleted file mode 100644 index bebc93863..000000000 Binary files a/front/.yarn/cache/braces-npm-3.0.3-582c14023c-fad11a0d46.zip and /dev/null differ diff --git a/front/.yarn/cache/date-fns-npm-2.30.0-895c790e0f-70b3e8ea7a.zip b/front/.yarn/cache/date-fns-npm-2.30.0-895c790e0f-70b3e8ea7a.zip new file mode 100644 index 000000000..b016f7bdd Binary files /dev/null and b/front/.yarn/cache/date-fns-npm-2.30.0-895c790e0f-70b3e8ea7a.zip differ diff --git a/front/.yarn/cache/date-fns-tz-npm-2.0.1-e8e605b668-f12e684bc1.zip b/front/.yarn/cache/date-fns-tz-npm-2.0.1-e8e605b668-f12e684bc1.zip new file mode 100644 index 000000000..4f9a95d93 Binary files /dev/null and b/front/.yarn/cache/date-fns-tz-npm-2.0.1-e8e605b668-f12e684bc1.zip differ diff --git a/front/.yarn/cache/fill-range-npm-7.0.1-b8b1817caa-e260f7592f.zip b/front/.yarn/cache/fill-range-npm-7.0.1-b8b1817caa-e260f7592f.zip new file mode 100644 index 000000000..7be5ed272 Binary files /dev/null and b/front/.yarn/cache/fill-range-npm-7.0.1-b8b1817caa-e260f7592f.zip differ diff --git a/front/.yarn/cache/fill-range-npm-7.1.1-bf491486db-a7095cb39e.zip b/front/.yarn/cache/fill-range-npm-7.1.1-bf491486db-a7095cb39e.zip deleted file mode 100644 index 2dbb57d46..000000000 Binary files a/front/.yarn/cache/fill-range-npm-7.1.1-bf491486db-a7095cb39e.zip and /dev/null differ diff --git a/front/.yarn/cache/tar-npm-6.2.1-237800bb20-bfbfbb2861.zip b/front/.yarn/cache/tar-npm-6.2.0-3eb25205a7-2042bbb148.zip similarity index 62% rename from front/.yarn/cache/tar-npm-6.2.1-237800bb20-bfbfbb2861.zip rename to front/.yarn/cache/tar-npm-6.2.0-3eb25205a7-2042bbb148.zip index 066f40476..194ce1253 100644 Binary files a/front/.yarn/cache/tar-npm-6.2.1-237800bb20-bfbfbb2861.zip and b/front/.yarn/cache/tar-npm-6.2.0-3eb25205a7-2042bbb148.zip differ diff --git a/front/.yarn/cache/v-calendar-npm-3.1.2-174a2bd698-47ff6fe81a.zip b/front/.yarn/cache/v-calendar-npm-3.1.2-174a2bd698-47ff6fe81a.zip new file mode 100644 index 000000000..d9206d27e Binary files /dev/null and b/front/.yarn/cache/v-calendar-npm-3.1.2-174a2bd698-47ff6fe81a.zip differ diff --git a/front/.yarn/cache/vue-demi-npm-0.14.10-d4a4eb175d-3028239c0c.zip b/front/.yarn/cache/vue-demi-npm-0.14.10-d4a4eb175d-3028239c0c.zip new file mode 100644 index 000000000..68f874e1f Binary files /dev/null and b/front/.yarn/cache/vue-demi-npm-0.14.10-d4a4eb175d-3028239c0c.zip differ diff --git a/front/.yarn/cache/vue-screen-utils-npm-1.0.0-beta.13-51a883c943-a4f527e7d1.zip b/front/.yarn/cache/vue-screen-utils-npm-1.0.0-beta.13-51a883c943-a4f527e7d1.zip new file mode 100644 index 000000000..fc4b2cfe8 Binary files /dev/null and b/front/.yarn/cache/vue-screen-utils-npm-1.0.0-beta.13-51a883c943-a4f527e7d1.zip differ diff --git a/front/.yarn/cache/webpack-dev-middleware-npm-5.3.4-74a86c7ece-3004374130.zip b/front/.yarn/cache/webpack-dev-middleware-npm-5.3.3-c3f195990d-31a2f7a11e.zip similarity index 59% rename from front/.yarn/cache/webpack-dev-middleware-npm-5.3.4-74a86c7ece-3004374130.zip rename to front/.yarn/cache/webpack-dev-middleware-npm-5.3.3-c3f195990d-31a2f7a11e.zip index ca5d9f52f..646342886 100644 Binary files a/front/.yarn/cache/webpack-dev-middleware-npm-5.3.4-74a86c7ece-3004374130.zip and b/front/.yarn/cache/webpack-dev-middleware-npm-5.3.3-c3f195990d-31a2f7a11e.zip differ diff --git a/front/graphql.schema.json b/front/graphql.schema.json index 5b22861a5..83a42762b 100644 --- a/front/graphql.schema.json +++ b/front/graphql.schema.json @@ -3786,6 +3786,145 @@ ], "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "CtftimeCtf", + "description": null, + "fields": [ + { + "name": "ctftimeUrl", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "finish", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "logo", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "start", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "title", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "url", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "weight", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Float", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, { "kind": "SCALAR", "name": "Cursor", @@ -9598,6 +9737,144 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "ctfsByDate", + "description": "Reads and enables pagination through a set of `Ctf`.", + "args": [ + { + "name": "after", + "description": "Read all values in the set after (below) this cursor.", + "type": { + "kind": "SCALAR", + "name": "Cursor", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "before", + "description": "Read all values in the set before (above) this cursor.", + "type": { + "kind": "SCALAR", + "name": "Cursor", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "filter", + "description": "A filter to be used in determining which values should be returned by the collection.", + "type": { + "kind": "INPUT_OBJECT", + "name": "CtfFilter", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "first", + "description": "Only read the first `n` values of the set.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "last", + "description": "Only read the last `n` values of the set.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "month", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "offset", + "description": "Skip the first `n` values from our `after` cursor, an alternative to cursor\nbased pagination. May not be used with `last`.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "year", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "OBJECT", + "name": "CtfsConnection", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ctftimeCtfById", + "description": null, + "args": [ + { + "name": "id", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "OBJECT", + "name": "CtftimeCtf", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "guests", "description": "Reads and enables pagination through a set of `Profile`.", diff --git a/front/package.json b/front/package.json index b0a8cc513..0abf1bf0a 100644 --- a/front/package.json +++ b/front/package.json @@ -15,11 +15,13 @@ }, "dependencies": { "@apollo/client": "^3.9.9", + "@popperjs/core": "^2.11.8", "@quasar/cli": "^2.4.0", "@quasar/extras": "^1.16.9", "@quasar/quasar-app-extension-apollo": "^2.2.0", "@quasar/quasar-ui-qcalendar": "^4.0.0-beta.19", "@vue/apollo-composable": "^4.0.2", + "@vueuse/core": "^11.0.1", "apollo-upload-client": "^17.0.0", "color-hash": "^2.0.2", "core-js": "^3.36.1", @@ -28,6 +30,7 @@ "quasar": "^2.16.6", "slugify": "^1.6.6", "ts-essentials": "^9.4.1", + "v-calendar": "^3.1.2", "vue": "^3.4.21", "vue-router": "^4.3.0" }, diff --git a/front/quasar.conf.js b/front/quasar.conf.js index 4044f3469..2abb4ffaa 100644 --- a/front/quasar.conf.js +++ b/front/quasar.conf.js @@ -28,7 +28,7 @@ module.exports = configure(function (ctx) { // app boot file (/src/boot) // --> boot files are part of "main.js" // https://v2.quasar.dev/quasar-cli/boot-files - boot: ['apollo', 'ctfnote'], + boot: ['apollo', 'ctfnote', 'vcalendar'], // https://v2.quasar.dev/quasar-cli/quasar-conf-js#Property%3A-css css: ['app.scss'], @@ -90,6 +90,9 @@ module.exports = configure(function (ctx) { '/calendar.ics': { target: 'http://127.0.0.1:3000', }, + '/ctftime': { + target: 'http://127.0.0.1:3000', + }, '/pad': { target: 'http://127.0.0.1:3001/', pathRewrite: { diff --git a/front/src/boot/vcalendar.ts b/front/src/boot/vcalendar.ts new file mode 100644 index 000000000..4afbd820e --- /dev/null +++ b/front/src/boot/vcalendar.ts @@ -0,0 +1,7 @@ +import { boot } from 'quasar/wrappers'; +import VCalendar from 'v-calendar'; +import 'v-calendar/style.css'; + +export default boot(({ app }) => { + app.use(VCalendar, {}); +}); diff --git a/front/src/components/CTF/BtnDelete.vue b/front/src/components/CTF/BtnDelete.vue index 41ee25f23..1b56520f4 100644 --- a/front/src/components/CTF/BtnDelete.vue +++ b/front/src/components/CTF/BtnDelete.vue @@ -2,6 +2,7 @@ - - -
- -
- -
{{ currentMonth }}
- - Copy iCalendar link - -
- -
-
-
- -
{{ currentMonth }}
- - Copy iCalendar link - -
- - -
-
- - - - - -
- - - - diff --git a/front/src/components/CTF/Card.vue b/front/src/components/CTF/Card.vue index eeb8e818d..eb0162fb1 100644 --- a/front/src/components/CTF/Card.vue +++ b/front/src/components/CTF/Card.vue @@ -1,5 +1,5 @@ - @@ -146,7 +125,76 @@ export default defineComponent({ } } -.running { - animation: blinker 0.5s ease-in infinite alternate; +.ctf-card { + --description-width: 800px; + max-width: 100%; + + .background-logo { + &::before { + content: ''; + background: var(--bgUrl); + background-position: 100% 50%; + background-size: contain; + background-repeat: no-repeat; + opacity: 0.3; + width: calc(100% - var(--description-width) - 48px); + height: 100%; + right: 16px; + position: absolute; + pointer-events: none; + } + } + + .ctf-card-description { + max-width: var(--description-width); + text-align: justify; + } + + .ctf-card-header { + display: grid; + grid-template-areas: 'logo title live space weight ctftime'; + grid-template-columns: auto auto auto 1fr auto auto auto; + gap: 8px; + align-items: center; + + @media (max-width: $breakpoint-sm-min) { + grid-template-areas: 'title title title title title' 'logo live space weight ctftime'; + grid-template-columns: auto auto 1fr auto auto; + } + + .ctf-card-header-logo { + grid-area: logo; + } + + .ctf-card-header-title { + grid-area: title; + max-width: 100%; + min-width: 0; + + @media (max-width: $breakpoint-sm-min) { + width: 100%; + } + } + + .ctf-card-header-weight { + grid-area: weight; + } + + .ctf-card-header-ctftime { + grid-area: ctftime; + --offset: 32px; + + @media (max-width: $breakpoint-sm-min) { + --offset: 24px; + } + transform: translateX(var(--offset)); + margin-left: calc(-1 * var(--offset)); + } + + .ctf-card-header-live { + grid-area: live; + animation: blinker 0.5s ease-in infinite alternate; + } + } } diff --git a/front/src/components/CTF/CardList.vue b/front/src/components/CTF/CardList.vue index e2675bf40..612d004c2 100644 --- a/front/src/components/CTF/CardList.vue +++ b/front/src/components/CTF/CardList.vue @@ -1,58 +1,208 @@ - + + diff --git a/front/src/components/CTF/CtfCalendar.vue b/front/src/components/CTF/CtfCalendar.vue new file mode 100644 index 000000000..143ec2673 --- /dev/null +++ b/front/src/components/CTF/CtfCalendar.vue @@ -0,0 +1,296 @@ + + + + + diff --git a/front/src/components/CTF/CtfTimeLink.vue b/front/src/components/CTF/CtfTimeLink.vue index 782b01a38..9e348b78b 100644 --- a/front/src/components/CTF/CtfTimeLink.vue +++ b/front/src/components/CTF/CtfTimeLink.vue @@ -1,16 +1,30 @@ - + + diff --git a/front/src/components/CTF/CtftimeInput.vue b/front/src/components/CTF/CtftimeInput.vue new file mode 100644 index 000000000..a80e3db72 --- /dev/null +++ b/front/src/components/CTF/CtftimeInput.vue @@ -0,0 +1,117 @@ + + + diff --git a/front/src/components/CTF/Incoming.vue b/front/src/components/CTF/Incoming.vue deleted file mode 100644 index 20760ca97..000000000 --- a/front/src/components/CTF/Incoming.vue +++ /dev/null @@ -1,57 +0,0 @@ - - - - - diff --git a/front/src/components/CTF/Info.vue b/front/src/components/CTF/Info.vue index b365206c3..de284f608 100644 --- a/front/src/components/CTF/Info.vue +++ b/front/src/components/CTF/Info.vue @@ -2,37 +2,24 @@