From 0b7e58a239cd07869b73315fb07338a55774de91 Mon Sep 17 00:00:00 2001 From: goo314 Date: Mon, 10 Jan 2022 22:24:27 +0900 Subject: [PATCH 01/24] refactor: Rebase --- frontend/src/pages/oj/router/routes.js | 9 ++++++++- frontend/src/pages/oj/views/index.js | 3 ++- .../src/pages/oj/views/user/ProfileContest.vue | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 frontend/src/pages/oj/views/user/ProfileContest.vue diff --git a/frontend/src/pages/oj/router/routes.js b/frontend/src/pages/oj/router/routes.js index f68d4aaec..ddb30f709 100644 --- a/frontend/src/pages/oj/router/routes.js +++ b/frontend/src/pages/oj/router/routes.js @@ -16,7 +16,8 @@ import { ProblemList, ResetPassword, ProfileSetting, - Profile + Profile, + ProfileContest } from '../views' export default [ @@ -122,6 +123,12 @@ export default [ meta: { requiresAuth: true, title: 'My Profile' }, component: Profile }, + { + name: 'profile-contest', + path: '/profile-contest', + component: ProfileContest, + meta: { title: 'Profile Contest' } + }, { path: '*', meta: { title: '404' }, diff --git a/frontend/src/pages/oj/views/index.js b/frontend/src/pages/oj/views/index.js index 6a508aafb..845818ded 100644 --- a/frontend/src/pages/oj/views/index.js +++ b/frontend/src/pages/oj/views/index.js @@ -7,6 +7,7 @@ import Home from './general/Home.vue' import ContestRanking from './contest/ContestRanking.vue' import ContestProblemList from './contest/ContestProblemList.vue' import Profile from './user/Profile.vue' +import ProfileContest from './user/ProfileContest.vue' // Grouping Components in the Same Chunk const Problem = () => import(/* webpackChunkName: "Problem" */ '@oj/views/problem/Problem.vue') @@ -27,7 +28,7 @@ export { Logout, ProblemList, Announcement, AnnouncementList, Problem, ApplyResetPassword, ResetPassword, EmailAuth, ProfileSetting, ContestList, ContestDetail, ContestProblemList, ContestRanking, Register, - Profile + Profile, ProfileContest } /* 구성 요소 내보내기는 두 가지 범주로 나뉩니다. * 하나는 일반적으로 직접 내보내기에 사용되며 diff --git a/frontend/src/pages/oj/views/user/ProfileContest.vue b/frontend/src/pages/oj/views/user/ProfileContest.vue new file mode 100644 index 000000000..b88530b9f --- /dev/null +++ b/frontend/src/pages/oj/views/user/ProfileContest.vue @@ -0,0 +1,18 @@ + + + + + From bc6c7ec19773c6f301bbcd0d1a11342211bbc12b Mon Sep 17 00:00:00 2001 From: goo314 Date: Tue, 11 Jan 2022 11:23:23 +0900 Subject: [PATCH 02/24] fix: Delete routers of profile-contest --- frontend/src/pages/oj/router/routes.js | 11 ++--------- frontend/src/pages/oj/views/index.js | 3 +-- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/frontend/src/pages/oj/router/routes.js b/frontend/src/pages/oj/router/routes.js index ddb30f709..d67e1b1c5 100644 --- a/frontend/src/pages/oj/router/routes.js +++ b/frontend/src/pages/oj/router/routes.js @@ -16,8 +16,7 @@ import { ProblemList, ResetPassword, ProfileSetting, - Profile, - ProfileContest + Profile } from '../views' export default [ @@ -120,15 +119,9 @@ export default [ { name: 'profile', path: '/profile', - meta: { requiresAuth: true, title: 'My Profile' }, + meta: { title: 'My Profile' }, component: Profile }, - { - name: 'profile-contest', - path: '/profile-contest', - component: ProfileContest, - meta: { title: 'Profile Contest' } - }, { path: '*', meta: { title: '404' }, diff --git a/frontend/src/pages/oj/views/index.js b/frontend/src/pages/oj/views/index.js index 845818ded..6a508aafb 100644 --- a/frontend/src/pages/oj/views/index.js +++ b/frontend/src/pages/oj/views/index.js @@ -7,7 +7,6 @@ import Home from './general/Home.vue' import ContestRanking from './contest/ContestRanking.vue' import ContestProblemList from './contest/ContestProblemList.vue' import Profile from './user/Profile.vue' -import ProfileContest from './user/ProfileContest.vue' // Grouping Components in the Same Chunk const Problem = () => import(/* webpackChunkName: "Problem" */ '@oj/views/problem/Problem.vue') @@ -28,7 +27,7 @@ export { Logout, ProblemList, Announcement, AnnouncementList, Problem, ApplyResetPassword, ResetPassword, EmailAuth, ProfileSetting, ContestList, ContestDetail, ContestProblemList, ContestRanking, Register, - Profile, ProfileContest + Profile } /* 구성 요소 내보내기는 두 가지 범주로 나뉩니다. * 하나는 일반적으로 직접 내보내기에 사용되며 From 07e6875ecc53c020c441e74603cc7f1b21795ae3 Mon Sep 17 00:00:00 2001 From: goo314 Date: Tue, 11 Jan 2022 22:40:55 +0900 Subject: [PATCH 03/24] feat: Add ProfileContest vue --- frontend/package.json | 1 + .../oj/components/user/ProfileContest.vue | 137 +++++++++++++++--- .../pages/oj/views/user/ProfileContest.vue | 18 --- frontend/yarn.lock | 5 + package-lock.json | 24 +++ package.json | 5 + 6 files changed, 152 insertions(+), 38 deletions(-) delete mode 100644 frontend/src/pages/oj/views/user/ProfileContest.vue create mode 100644 package-lock.json create mode 100644 package.json diff --git a/frontend/package.json b/frontend/package.json index ac7b53b15..f4040bebf 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,6 +16,7 @@ "axios": "^0.24.0", "bootstrap-vue": "^2.21.2", "browser-detect": "^0.2.28", + "chart.js": "^3.7.0", "core-js": "^3.19.3", "highlight.js": "10.7.3", "iview": "2", diff --git a/frontend/src/pages/oj/components/user/ProfileContest.vue b/frontend/src/pages/oj/components/user/ProfileContest.vue index 1af2953b0..6c5fd1cd5 100644 --- a/frontend/src/pages/oj/components/user/ProfileContest.vue +++ b/frontend/src/pages/oj/components/user/ProfileContest.vue @@ -1,38 +1,135 @@ + diff --git a/frontend/src/pages/oj/views/user/ProfileContest.vue b/frontend/src/pages/oj/views/user/ProfileContest.vue deleted file mode 100644 index b88530b9f..000000000 --- a/frontend/src/pages/oj/views/user/ProfileContest.vue +++ /dev/null @@ -1,18 +0,0 @@ - - - - - diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 83d425e71..e08c4cbd5 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -2752,6 +2752,11 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +chart.js@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.7.0.tgz#7a19c93035341df801d613993c2170a1fcf1d882" + integrity sha512-31gVuqqKp3lDIFmzpKIrBeum4OpZsQjSIAqlOpgjosHDJZlULtvwLEZKtEhIAZc7JMPaHlYMys40Qy9Mf+1AAg== + check-types@^8.0.3: version "8.0.3" resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552" diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..f156e3265 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,24 @@ +{ + "name": "workspace", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "dependencies": { + "chart.js": "^3.7.0" + } + }, + "node_modules/chart.js": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.0.tgz", + "integrity": "sha512-31gVuqqKp3lDIFmzpKIrBeum4OpZsQjSIAqlOpgjosHDJZlULtvwLEZKtEhIAZc7JMPaHlYMys40Qy9Mf+1AAg==" + } + }, + "dependencies": { + "chart.js": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.0.tgz", + "integrity": "sha512-31gVuqqKp3lDIFmzpKIrBeum4OpZsQjSIAqlOpgjosHDJZlULtvwLEZKtEhIAZc7JMPaHlYMys40Qy9Mf+1AAg==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..94c6ea5ef --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "chart.js": "^3.7.0" + } +} From b9b44af40a6e789e3e016c601fc86dee722a9490 Mon Sep 17 00:00:00 2001 From: goo314 Date: Fri, 14 Jan 2022 21:14:13 +0900 Subject: [PATCH 04/24] feat: Publish user contest page --- .../pages/oj/components/user/ProfileContest.vue | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/oj/components/user/ProfileContest.vue b/frontend/src/pages/oj/components/user/ProfileContest.vue index 6c5fd1cd5..dec360923 100644 --- a/frontend/src/pages/oj/components/user/ProfileContest.vue +++ b/frontend/src/pages/oj/components/user/ProfileContest.vue @@ -7,6 +7,14 @@ +
+ + All + Rank + Prize + +
+
@@ -120,9 +128,16 @@ export default { .rank-chart { width: 80%; } -.table { + +.sort-container { width: 95%; margin-top: 30px; + display: flex; + justify-content: flex-end !important; +} + +.table { + width: 95%; cursor: pointer; } .pagination { From 365c56f287049cef1a5491febbb80434c868341e Mon Sep 17 00:00:00 2001 From: goo314 Date: Fri, 14 Jan 2022 21:19:38 +0900 Subject: [PATCH 05/24] add: Add file in gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index abffbd4d1..f3c4fa0f4 100644 --- a/.gitignore +++ b/.gitignore @@ -196,3 +196,6 @@ typings/ # devcontainer .devcontainer/data + +# MacOS file +.DS_Store From 1867d427abb1241464611db7ac6ff381af363e76 Mon Sep 17 00:00:00 2001 From: goo314 Date: Fri, 21 Jan 2022 21:55:01 +0900 Subject: [PATCH 06/24] feat: Add Pagination component --- .../src/pages/oj/components/Pagination.vue | 45 +++++++++++++++++++ .../oj/components/user/ProfileContest.vue | 7 ++- 2 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 frontend/src/pages/oj/components/Pagination.vue diff --git a/frontend/src/pages/oj/components/Pagination.vue b/frontend/src/pages/oj/components/Pagination.vue new file mode 100644 index 000000000..8a8308336 --- /dev/null +++ b/frontend/src/pages/oj/components/Pagination.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/frontend/src/pages/oj/components/user/ProfileContest.vue b/frontend/src/pages/oj/components/user/ProfileContest.vue index dec360923..f62d88493 100644 --- a/frontend/src/pages/oj/components/user/ProfileContest.vue +++ b/frontend/src/pages/oj/components/user/ProfileContest.vue @@ -36,16 +36,18 @@ limit="3" >
+ From 606cd19d18842e5e81372cebe02bf1a76a1f74e6 Mon Sep 17 00:00:00 2001 From: goo314 Date: Fri, 28 Jan 2022 13:59:19 +0900 Subject: [PATCH 08/24] chore: Remove chart.js outside frontend folder --- package-lock.json | 24 ------------------------ package.json | 5 ----- 2 files changed, 29 deletions(-) delete mode 100644 package-lock.json delete mode 100644 package.json diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index f156e3265..000000000 --- a/package-lock.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "workspace", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "dependencies": { - "chart.js": "^3.7.0" - } - }, - "node_modules/chart.js": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.0.tgz", - "integrity": "sha512-31gVuqqKp3lDIFmzpKIrBeum4OpZsQjSIAqlOpgjosHDJZlULtvwLEZKtEhIAZc7JMPaHlYMys40Qy9Mf+1AAg==" - } - }, - "dependencies": { - "chart.js": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.0.tgz", - "integrity": "sha512-31gVuqqKp3lDIFmzpKIrBeum4OpZsQjSIAqlOpgjosHDJZlULtvwLEZKtEhIAZc7JMPaHlYMys40Qy9Mf+1AAg==" - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 94c6ea5ef..000000000 --- a/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "dependencies": { - "chart.js": "^3.7.0" - } -} From cdba9550a2f76c09d16c7665cf85a0c456a8de11 Mon Sep 17 00:00:00 2001 From: goo314 Date: Fri, 28 Jan 2022 18:11:47 +0900 Subject: [PATCH 09/24] fix: Show at most limit pages --- .../src/pages/oj/components/Pagination.vue | 87 ++++++++++++------- 1 file changed, 57 insertions(+), 30 deletions(-) diff --git a/frontend/src/pages/oj/components/Pagination.vue b/frontend/src/pages/oj/components/Pagination.vue index af8714d50..b44bcdb4e 100644 --- a/frontend/src/pages/oj/components/Pagination.vue +++ b/frontend/src/pages/oj/components/Pagination.vue @@ -1,11 +1,17 @@ @@ -14,32 +20,39 @@ export default { name: 'Pagination', props: {}, + data () { + return { + rows: 45, // number of total rows in table + perPage: 3, // number of rows in table per one page + currentPage: 1, + limit: 3 // maximum of number of pages + } + }, methods: { - toFront: function () { - console.log('front') - this.currentPage = 1 - }, - toPrev: function () { - console.log('prev') - if (this.currentPage > 1) { - this.currentPage -= 1 - } - }, - toNext: function () { - console.log('next') - if (this.currentPage < this.limit) { - this.currentPage += 1 + changePage (page) { + if (page >= 1 && page <= this.numberOfPages) { + this.currentPage = page } - }, - toEnd: function () { - console.log('end') - this.currentPage = this.limit } }, - data () { - return { - limit: 5, - currentPage: 3 + computed: { + numberOfPages () { // number of pages (if 9 rows and 3 for each pages, then 3 pages) + return Math.ceil(this.rows / this.perPage) + }, + startPage () { + var start = (Math.trunc((this.currentPage - 1) / this.limit)) * this.limit + 1 + return start + }, + endPage () { + var end = this.startPage + this.limit - 1 + return end < this.numberOfPages ? end : this.numberOfPages + }, + pageList () { + var pages = [] + for (let i = this.startPage; i <= this.endPage; i++) { + pages.push(i) + } + return pages } } } @@ -56,7 +69,7 @@ export default { .page-itm { border-radius: 50rem !important; - padding: 0.25rem; + margin: 20px 5% 16px 0; display: flex; flex-direction: row; } @@ -66,15 +79,29 @@ export default { height: 30px; text-align: center; line-height: 25px; - margin-right: 0.25rem; + margin-left: 0.25rem; border-radius: 5px !important; color: #bdbdbd; border: thin solid #bdbdbd; cursor: pointer; } -.page-btn:hover{ +.page-btn:hover { background-color: #bdbdbd; color: white; } + +.select-page-btn { + width: 30px; + height: 30px; + text-align: center; + line-height: 25px; + margin-left: 0.25rem; + border-radius: 5px !important; + background-color: #bdbdbd; + color: white; + border: thin solid #bdbdbd; + cursor: pointer; +} + From 0e421b41feff970b1495e6598932a6619438ce31 Mon Sep 17 00:00:00 2001 From: goo314 Date: Fri, 28 Jan 2022 18:53:59 +0900 Subject: [PATCH 10/24] style: Shorten style code --- .../src/pages/oj/components/Pagination.vue | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/frontend/src/pages/oj/components/Pagination.vue b/frontend/src/pages/oj/components/Pagination.vue index b44bcdb4e..139b00571 100644 --- a/frontend/src/pages/oj/components/Pagination.vue +++ b/frontend/src/pages/oj/components/Pagination.vue @@ -1,17 +1,17 @@ @@ -86,22 +86,14 @@ export default { cursor: pointer; } -.page-btn:hover { - background-color: #bdbdbd; - color: white; +.page-btn.select { + background-color: #bdbdbd; + color: white; } -.select-page-btn { - width: 30px; - height: 30px; - text-align: center; - line-height: 25px; - margin-left: 0.25rem; - border-radius: 5px !important; +.page-btn:hover { background-color: #bdbdbd; color: white; - border: thin solid #bdbdbd; - cursor: pointer; } From 6694e96e128cb4b1e31406676adab04b25519c0a Mon Sep 17 00:00:00 2001 From: goo314 Date: Sat, 29 Jan 2022 01:58:21 +0900 Subject: [PATCH 11/24] fix: Add component communication(props, event) --- .../src/pages/oj/components/Pagination.vue | 89 ++++++++++--------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/frontend/src/pages/oj/components/Pagination.vue b/frontend/src/pages/oj/components/Pagination.vue index 139b00571..f3c95b3f0 100644 --- a/frontend/src/pages/oj/components/Pagination.vue +++ b/frontend/src/pages/oj/components/Pagination.vue @@ -1,51 +1,57 @@ From fc89247e39418ab9210fb01563aad3b5488596a3 Mon Sep 17 00:00:00 2001 From: goo314 Date: Sat, 29 Jan 2022 01:59:17 +0900 Subject: [PATCH 12/24] style: Apply Pagination vue --- .../pages/oj/components/user/ProfileContest.vue | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/frontend/src/pages/oj/components/user/ProfileContest.vue b/frontend/src/pages/oj/components/user/ProfileContest.vue index f62d88493..a7ed0300b 100644 --- a/frontend/src/pages/oj/components/user/ProfileContest.vue +++ b/frontend/src/pages/oj/components/user/ProfileContest.vue @@ -29,14 +29,13 @@ - @@ -51,6 +50,9 @@ export default { props: {}, data() { return { + rows: 100, + currentPage: 1, + perPage: 3, Chart, fields: [ { key: "date", label: "Date" }, From eea45dd45c1602cb5125e67c049e04330b9b684c Mon Sep 17 00:00:00 2001 From: goo314 Date: Sun, 6 Feb 2022 21:31:44 +0900 Subject: [PATCH 13/24] style: Edit code style --- .../src/pages/oj/components/Pagination.vue | 22 +++++++++---------- frontend/src/pages/oj/router/routes.js | 2 +- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/frontend/src/pages/oj/components/Pagination.vue b/frontend/src/pages/oj/components/Pagination.vue index f3c95b3f0..3475c767a 100644 --- a/frontend/src/pages/oj/components/Pagination.vue +++ b/frontend/src/pages/oj/components/Pagination.vue @@ -42,23 +42,20 @@ export default { } }, computed: { + localLimit () { + return Number(this.limit) + }, numberOfPages () { // number of pages return Math.ceil(this.totalRows / this.perPage) }, startPage () { - var start = (Math.trunc((this.currentPage - 1) / this.limit)) * this.limit + 1 - return start + return Math.trunc((this.currentPage - 1) / this.localLimit) * this.localLimit + 1 }, endPage () { - var end = this.startPage + Number(this.limit) - 1 - return end <= this.numberOfPages ? end : this.numberOfPages + return this.startPage + this.localLimit - 1 <= this.numberOfPages ? this.startPage + this.localLimit - 1 : this.numberOfPages }, pageList () { - var pages = [] - for (let i = this.startPage; i <= this.endPage; i++) { - pages.push(i) - } - return pages + return [...Array(this.endPage - this.startPage + 1).keys()].map(i => i + this.startPage) } } } @@ -84,21 +81,22 @@ export default { cursor: pointer; } -.page-btn.leftedge { +.leftedge { border-top-left-radius: 0.25rem !important; border-bottom-left-radius: 0.25rem !important; } -.page-btn.rightedge { +.rightedge { border-top-right-radius: 0.25rem !important; border-bottom-right-radius: 0.25rem !important; } -.page-btn.select { +.select { background-color: #bdbdbd; border: thin solid #bdbdbd; color: white; pointer-events: none; + z-index: 1; } .page-btn:hover { diff --git a/frontend/src/pages/oj/router/routes.js b/frontend/src/pages/oj/router/routes.js index d67e1b1c5..f68d4aaec 100644 --- a/frontend/src/pages/oj/router/routes.js +++ b/frontend/src/pages/oj/router/routes.js @@ -119,7 +119,7 @@ export default [ { name: 'profile', path: '/profile', - meta: { title: 'My Profile' }, + meta: { requiresAuth: true, title: 'My Profile' }, component: Profile }, { From 91e7d1e87935c9455d62b2bebb862a866cd26936 Mon Sep 17 00:00:00 2001 From: goo314 Date: Tue, 8 Feb 2022 12:23:05 +0000 Subject: [PATCH 14/24] feat: Create USerContestAPI --- .DS_Store | Bin 0 -> 8196 bytes backend/.DS_Store | Bin 0 -> 10244 bytes backend/contest/serializers.py | 5 +++++ backend/contest/urls/oj.py | 2 ++ backend/contest/views/oj.py | 16 ++++++++++++++++ 5 files changed, 23 insertions(+) create mode 100644 .DS_Store create mode 100644 backend/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..39783ed22f1727a4b602018752105c09a3e835be GIT binary patch literal 8196 zcmeHM%W4!s6uqSr)1cxb1VZAX1=rD8C;=B~!}tY3vNV|)O=KP&lFWd+{s0$AR`~%D z9~<4c6%%IRN*9VC{)3>n$jVc^Ci>Uu)#OjJvw20f|4Khv3IC0pJYE7fu zkZV%g%w}gH_{`e+v8{NZByU~jH4klC8a>EME7YN?%#OFo9Zb& z`@1h#Pl_S+Y|UP|+1GQ3HPBPcl6uVb_tu{hp7JGoIwh5iJQ}|$*QAE$y~(|=Z~b%P zW99DTt;@V4+q^FU-KRBwGL~`T+@-Au`7<1;V`2ZUh9>$eAr`~mM?DW{L!h1{q{)8`e)7U2eF#p(&fBEpqILA9%da8ueJ2-_62>Ny{G=6z@GO&3xv&K>T3^}f$J&vTyhF`gq4sgBWn zJ5fMHjktB(-i$}grStl(xl-=UX+(wcM58oFBLi34JNv>Kw143p@D6wfyaV0=@4)}y z0KT*J)wtD0|MU)c2fPDi2lV<7;MOtgV#!9cbl_pO0EqQ?Z7%$beSj$wxR`aZWTPpH zI_>U3xuVK#F_bNie4ycoSr?ju)IH|0S{^=d?4%9lJ_wE_$ zp+0;vBqIvIz`Zva)ircVnTTiVRtX6PBj z$Li^$ek$NDpDZ{mU4916L@d{M@xjgyUtb%If52DNZUirMt2s!aCg>i<=Q>@5+E~p~ zpOSD~@8sI8F6U`%orSQXbv>-q*{yXpP_J{ipN8ydP2_3Y&+0ta)wL~*bcs5+o+OOa z5ojItX3P!J6{+FlZJy)&XTR?`>U=4e<=k<3!J9JUE8}=aFsg>5^D5_nD*gg{6@qK% zJ1`t+s6kbFB^f33)R{@v;O5>C)bvX)o*#i4k>^^TzPnfH4?BNN9o&;7jL@Opg9iPP z$G8}w9;xB{7oOw%EjL$o%)B)7s$7R;ZErN4r=)|E} zJJze};VP0*QqMW7r)c`U7b73val(Pr_>$2h5L{1s>O$m22CdTL$JN92B%_3$w9(Uq z^=A~d6yT8k9)nLpmD;7}V=RtqyFb4WX-mLXM#*|up)<9reM>{7?!|$sK5RMDEwfxx zzI7$i#L9E8;t_(sbrl3yC&$oVgES_*d9#?|InKQ>J+Yj&ey#DeI zcn7=#-U08xW;jr1D+%=Z|Ec8v|8EABufsdw9r#ZjQ1!XaTnEItv-KL8`m8;`-Hlsc z8dtK>6v4wB$0M5Kc>JPI4fo;J*ft&Yg`cx7mTbfuTz~za0XSz6e_zv_mZ8ru{Qkdk a8cTlvpDUkWC-3a}PA(ZG#+&;0`~Tm6_5pYR literal 0 HcmV?d00001 diff --git a/backend/contest/serializers.py b/backend/contest/serializers.py index 356cddaee..4d67afdc8 100644 --- a/backend/contest/serializers.py +++ b/backend/contest/serializers.py @@ -106,3 +106,8 @@ class ACMContesHelperSerializer(serializers.Serializer): problem_id = serializers.CharField() rank_id = serializers.IntegerField() checked = serializers.BooleanField() + +class UserContestSerializer(serializers.Serializer): + id = serializers.IntegerField() + title = serializers.CharField(max_length=128) + start_time = serializers.DateTimeField() diff --git a/backend/contest/urls/oj.py b/backend/contest/urls/oj.py index 9e82b81bd..6a3f768d3 100644 --- a/backend/contest/urls/oj.py +++ b/backend/contest/urls/oj.py @@ -3,6 +3,7 @@ from ..views.oj import ContestAnnouncementListAPI from ..views.oj import ContestPasswordVerifyAPI, ContestAccessAPI from ..views.oj import ContestListAPI, ContestAPI, ContestRankAPI +from ..views.oj import UserContestAPI urlpatterns = [ path("contests/", ContestListAPI.as_view(), name="contest_list_api"), @@ -11,4 +12,5 @@ path("contest/announcement/", ContestAnnouncementListAPI.as_view(), name="contest_announcement_api"), path("contest/access/", ContestAccessAPI.as_view(), name="contest_access_api"), path("contest/rank/", ContestRankAPI.as_view(), name="contest_rank_api"), + path("contest/user/", UserContestAPI.as_view(), name="contest_user_api"), ] diff --git a/backend/contest/views/oj.py b/backend/contest/views/oj.py index 9e82647e8..7299829c2 100644 --- a/backend/contest/views/oj.py +++ b/backend/contest/views/oj.py @@ -14,6 +14,7 @@ from ..serializers import ContestAnnouncementSerializer from ..serializers import ContestSerializer, ContestPasswordVerifySerializer from ..serializers import ACMContestRankSerializer +from ..serializers import UserContestSerializer class ContestAnnouncementListAPI(APIView): @@ -229,3 +230,18 @@ def get(self, request): page_qs["results"] = serializer(page_qs["results"], many=True, is_contest_admin=is_contest_admin).data page_qs["results"].append(self.contest.id) return self.success(page_qs) + +class UserContestAPI(APIView): + def get(self, request): + user = request.user + qs = ACMContestRank.objects.filter(user = user.id, user__admin_type=AdminType.REGULAR_USER, user__is_disabled=False).\ + select_related("user").order_by("-accepted_number", "total_penalty", "total_time") + contest_ids = [ dic['contest'] for dic in ACMContestRankSerializer(qs, many=True).data ] + contests = [] + for contest_id in contest_ids: + try: + contest = Contest.objects.get(id=contest_id, visible=True) + contests.append(contest) + except Contest.DoesNotExist: + return self.error("Contest does not exist") + return self.success(UserContestSerializer(contests, many=True).data) From 9a04321c7ea4231bfc8bbd3c687f8b8dc115da7c Mon Sep 17 00:00:00 2001 From: goo314 Date: Wed, 9 Feb 2022 06:30:59 +0000 Subject: [PATCH 15/24] add: Calate and return user rank in UserContestAPI --- backend/contest/serializers.py | 2 ++ backend/contest/views/oj.py | 20 +++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/backend/contest/serializers.py b/backend/contest/serializers.py index 4d67afdc8..354aaabf6 100644 --- a/backend/contest/serializers.py +++ b/backend/contest/serializers.py @@ -111,3 +111,5 @@ class UserContestSerializer(serializers.Serializer): id = serializers.IntegerField() title = serializers.CharField(max_length=128) start_time = serializers.DateTimeField() + rank = serializers.IntegerField() + percentage = serializers.FloatField() diff --git a/backend/contest/views/oj.py b/backend/contest/views/oj.py index 7299829c2..1a1dd92f4 100644 --- a/backend/contest/views/oj.py +++ b/backend/contest/views/oj.py @@ -232,15 +232,29 @@ def get(self, request): return self.success(page_qs) class UserContestAPI(APIView): + def get(self, request): user = request.user - qs = ACMContestRank.objects.filter(user = user.id, user__admin_type=AdminType.REGULAR_USER, user__is_disabled=False).\ - select_related("user").order_by("-accepted_number", "total_penalty", "total_time") - contest_ids = [ dic['contest'] for dic in ACMContestRankSerializer(qs, many=True).data ] + # queryset for all problems information which user submitted + qs_problems = ACMContestRank.objects.filter(user = user.id, user__admin_type=AdminType.REGULAR_USER, user__is_disabled=False) + # list for contest id which user participated + contest_ids = [ dic['contest'] for dic in ACMContestRankSerializer(qs_problems, many=True).data ] + # contest object information about each contest id contests = [] for contest_id in contest_ids: try: contest = Contest.objects.get(id=contest_id, visible=True) + contest = ContestSerializer(contest).data + # to calculate rank + qs_participants = ACMContestRank.objects.filter(contest=contest_id, user__admin_type=AdminType.REGULAR_USER, user__is_disabled=False).\ + select_related("user").order_by("-accepted_number", "total_penalty", "total_time") + participants = ACMContestRankSerializer(qs_participants, many=True).data + total_participants = len(participants) + for i in range(total_participants): + if participants[i]['user']['id'] == user.id: + contest['rank'] = i+1 + contest['percentage'] = contest['rank']/(total_participants)*100 + break contests.append(contest) except Contest.DoesNotExist: return self.error("Contest does not exist") From 79abf473b738f6f335db29088130ca0a850e9087 Mon Sep 17 00:00:00 2001 From: goo314 Date: Thu, 10 Feb 2022 04:27:27 +0000 Subject: [PATCH 16/24] style: Change code style --- backend/contest/serializers.py | 1 + backend/contest/views/oj.py | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/backend/contest/serializers.py b/backend/contest/serializers.py index 354aaabf6..c20b812f1 100644 --- a/backend/contest/serializers.py +++ b/backend/contest/serializers.py @@ -107,6 +107,7 @@ class ACMContesHelperSerializer(serializers.Serializer): rank_id = serializers.IntegerField() checked = serializers.BooleanField() + class UserContestSerializer(serializers.Serializer): id = serializers.IntegerField() title = serializers.CharField(max_length=128) diff --git a/backend/contest/views/oj.py b/backend/contest/views/oj.py index 1a1dd92f4..b9460690a 100644 --- a/backend/contest/views/oj.py +++ b/backend/contest/views/oj.py @@ -231,14 +231,14 @@ def get(self, request): page_qs["results"].append(self.contest.id) return self.success(page_qs) -class UserContestAPI(APIView): +class UserContestAPI(APIView): def get(self, request): user = request.user # queryset for all problems information which user submitted - qs_problems = ACMContestRank.objects.filter(user = user.id, user__admin_type=AdminType.REGULAR_USER, user__is_disabled=False) + qs_problems = ACMContestRank.objects.filter(user=user.id, user__admin_type=AdminType.REGULAR_USER, user__is_disabled=False) # list for contest id which user participated - contest_ids = [ dic['contest'] for dic in ACMContestRankSerializer(qs_problems, many=True).data ] + contest_ids = [dic["contest"] for dic in ACMContestRankSerializer(qs_problems, many=True).data] # contest object information about each contest id contests = [] for contest_id in contest_ids: @@ -251,9 +251,9 @@ def get(self, request): participants = ACMContestRankSerializer(qs_participants, many=True).data total_participants = len(participants) for i in range(total_participants): - if participants[i]['user']['id'] == user.id: - contest['rank'] = i+1 - contest['percentage'] = contest['rank']/(total_participants)*100 + if participants[i]["user"]["id"] == user.id: + contest["rank"] = i+1 + contest["percentage"] = contest["rank"]/(total_participants)*100 break contests.append(contest) except Contest.DoesNotExist: From 2d0308854be078f315edd43c11a6f74837f430e9 Mon Sep 17 00:00:00 2001 From: goo314 Date: Thu, 10 Feb 2022 07:09:37 +0000 Subject: [PATCH 17/24] add: Add rank field in ACMContestRank & Shorten UserContestAPI --- backend/contest/models.py | 13 +++++++++++++ backend/contest/views/oj.py | 19 +++++-------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/backend/contest/models.py b/backend/contest/models.py index 7ca53bd6f..d6cbf9716 100644 --- a/backend/contest/models.py +++ b/backend/contest/models.py @@ -7,6 +7,8 @@ from account.models import User from utils.models import RichTextField +from account.models import AdminType + class Contest(models.Model): title = models.TextField() @@ -73,6 +75,17 @@ class ACMContestRank(AbstractContestRank): # key is problem id submission_info = JSONField(default=dict) + @property + def rank(self): + qs_contest = Contest.objects.get(id=self.contest.id) + if qs_contest.status == ContestStatus.CONTEST_ENDED: + qs_participants = ACMContestRank.objects.filter(contest=self.contest.id, user__admin_type=AdminType.REGULAR_USER, user__is_disabled=False).\ + select_related("user").order_by("-accepted_number", "total_penalty", "total_time") + for i in range(qs_participants.count()): + if qs_participants[i].user.id == self.user.id: + return i+1 + return -1 + class Meta: db_table = "acm_contest_rank" unique_together = (("user", "contest"),) diff --git a/backend/contest/views/oj.py b/backend/contest/views/oj.py index b9460690a..edeb2cedd 100644 --- a/backend/contest/views/oj.py +++ b/backend/contest/views/oj.py @@ -237,24 +237,15 @@ def get(self, request): user = request.user # queryset for all problems information which user submitted qs_problems = ACMContestRank.objects.filter(user=user.id, user__admin_type=AdminType.REGULAR_USER, user__is_disabled=False) - # list for contest id which user participated - contest_ids = [dic["contest"] for dic in ACMContestRankSerializer(qs_problems, many=True).data] - # contest object information about each contest id contests = [] - for contest_id in contest_ids: + for problem in qs_problems: + contest_id = problem.contest.id try: contest = Contest.objects.get(id=contest_id, visible=True) contest = ContestSerializer(contest).data - # to calculate rank - qs_participants = ACMContestRank.objects.filter(contest=contest_id, user__admin_type=AdminType.REGULAR_USER, user__is_disabled=False).\ - select_related("user").order_by("-accepted_number", "total_penalty", "total_time") - participants = ACMContestRankSerializer(qs_participants, many=True).data - total_participants = len(participants) - for i in range(total_participants): - if participants[i]["user"]["id"] == user.id: - contest["rank"] = i+1 - contest["percentage"] = contest["rank"]/(total_participants)*100 - break + total_participants = ACMContestRank.objects.filter(contest=contest_id, user__admin_type=AdminType.REGULAR_USER, user__is_disabled=False).count() + contest["rank"] = problem.rank + contest["percentage"] = round(contest["rank"]/total_participants*100, 2) contests.append(contest) except Contest.DoesNotExist: return self.error("Contest does not exist") From 61456b6bdcd563566f1608cc40bd74dd133cb604 Mon Sep 17 00:00:00 2001 From: goo314 Date: Mon, 14 Feb 2022 23:47:33 +0900 Subject: [PATCH 18/24] add: Connect UserContestAPI to ProfileContest page --- frontend/src/pages/oj/api.js | 3 + .../oj/components/user/ProfileContest.vue | 89 ++++++++++--------- 2 files changed, 51 insertions(+), 41 deletions(-) diff --git a/frontend/src/pages/oj/api.js b/frontend/src/pages/oj/api.js index a74f161c6..a9e4c5945 100644 --- a/frontend/src/pages/oj/api.js +++ b/frontend/src/pages/oj/api.js @@ -213,6 +213,9 @@ export default { } }) }, + getUserContestInfo () { + return ajax('contest/user/', 'get') + }, submitCode (data) { return ajax('submission/', 'post', { data diff --git a/frontend/src/pages/oj/components/user/ProfileContest.vue b/frontend/src/pages/oj/components/user/ProfileContest.vue index a7ed0300b..a1194ef69 100644 --- a/frontend/src/pages/oj/components/user/ProfileContest.vue +++ b/frontend/src/pages/oj/components/user/ProfileContest.vue @@ -16,16 +16,24 @@
- - - @@ -136,6 +149,7 @@ export default { flex-direction: column; align-items: center; } + .rank-chart { width: 90%; } @@ -152,6 +166,11 @@ export default { margin: 0 auto; cursor: pointer; } + +.underwayClass { + backgroundColor: red; +} + .pagination { width: 95%; margin-right: 5%; From 8facf456a4cf0ca252ad1711847e4964ee428e29 Mon Sep 17 00:00:00 2001 From: goo314 Date: Sat, 26 Feb 2022 12:26:09 +0900 Subject: [PATCH 21/24] feat: Add test for user-contest-api --- .DS_Store | Bin 8196 -> 8196 bytes backend/.DS_Store | Bin 10244 -> 10244 bytes backend/contest/tests.py | 65 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/.DS_Store b/.DS_Store index 39783ed22f1727a4b602018752105c09a3e835be..7c927092288a2f87bb116e6afc60ad78d46701f6 100644 GIT binary patch delta 295 zcmZp1XmQwJA;45zGBE|!gPYX!JmFOul?Ef(P2ka`4qhJ1sR6H$@#ejKs^kMT@I6-1(g`*OimN*V`Ba}`J12|Tgv7Y zIn}o&I|zwP))V4EaGja|$*iB;CM3tUR%@zO%B{&4fGYL@RlvE5^3EVrfo@GlKR)aT delta 295 zcmZp1XmQwJA;2VkZSp(;xyca%MT`lPPYX!JWgBKQFfgz%=rN=-WHOZG=DWBg<>V&; z#W*Y`l!kNMIP8cjpMqDuAj2>?IX|}msE2{El3}v5pc3PU$!UUpOl*pizX{5*NqxR* z!Es}gy9eF7oPF~trcXkRm1)3F5Yxg9L zP!6v$U%wYCIyg44*c?$TXENDBISWtQiM7Y4av$Fu4~xogBC2vx?G{+HWDVU=C-{`` zGJJA0N<|#O&Vr4l`My8Ja*k)`x<7n*t2svYT`bqxZYEyvZc!ppJ9tmwHBMt-8_K!w zQ&b%1dw=&MU(?V&IoH3%3ZA5Swo=wAJW7*hx5n3W=S}bve$MMkF5uM=Q`askCWJ>^ z*IbD%2oB!iOW+XrIR3_wC%!JsU&jvf3)~obR`srG9rc8&n)3IntO6~A=b9rphiu2s z^AA>Sy^DVMtVBl%K8ZQSr`6tjlVCF{w4gKB8~vQi!Wx?obN}i-IFqOt!Gpdj9&yT} zE~aTjau}cIK91jWb+v0@Nox`0a_lg_z>VAS=P?r%DqvPFOYB{@_4t{e*JGGp;-=6wCGfnM)K9yLL_Ymq zdO3FY$whzcET4}&JVN5@c~8&;p8R>RXsEvR?;1bwa{OO60_|Bo#}AJX_}(x8@Jp~v z6LRFG;5x^omjR~E;b@IMiBnVkC4o~xeUHPI8fW>|tL6xfoup%j9-3Nj=!dh2juL## zkJlvFsCmz#^6?!f6o?(Tqxpyk&gbs6Xa4**^uzf?M+rWyx(?d${HcOX5ek{_G3X>% zc}G=6hQ@Jjd+sgy+#+J@_sHL31<%+r;BmiH^(+<|=CJ4UhV*hyUvtlWPAs2m6&@k* z_YEujIL%{|BP~|KAEI*N0QUDX>iy@Zy=FOh3rkz4a!VYPpiaF^oes6<0G>r{JVlG_ZO* r9v{?p{9YU?_Moz=;eFcLnz6Wo_Rs$ez&?ZceeKr&ZvFqCt^a=mxNH?_ literal 10244 zcmeHMO-oc!7=F*_IA#)2t5)4wXtYV8pf6&Q35qs_P;Cr9#=da8gJ0kx7;+I*L?nns z>p(&fBEpqILA9%da8ueJ2-_62>Ny{G=6z@GO&3xv&K>T3^}f$J&vTyhF`gq4sgBWn zJ5fMHjktB(-i$}grStl(xl-=UX+(wcM58oFBLi34JNv>Kw143p@D6wfyaV0=@4)}y z0KT*J)wtD0|MU)c2fPDi2lV<7;MOtgV#!9cbl_pO0EqQ?Z7%$beSj$wxR`aZWTPpH zI_>U3xuVK#F_bNie4ycoSr?ju)IH|0S{^=d?4%9lJ_wE_$ zp+0;vBqIvIz`Zva)ircVnTTiVRtX6PBj z$Li^$ek$NDpDZ{mU4916L@d{M@xjgyUtb%If52DNZUirMt2s!aCg>i<=Q>@5+E~p~ zpOSD~@8sI8F6U`%orSQXbv>-q*{yXpP_J{ipN8ydP2_3Y&+0ta)wL~*bcs5+o+OOa z5ojItX3P!J6{+FlZJy)&XTR?`>U=4e<=k<3!J9JUE8}=aFsg>5^D5_nD*gg{6@qK% zJ1`t+s6kbFB^f33)R{@v;O5>C)bvX)o*#i4k>^^TzPnfH4?BNN9o&;7jL@Opg9iPP z$G8}w9;xB{7oOw%EjL$o%)B)7s$7R;ZErN4r=)|E} zJJze};VP0*QqMW7r)c`U7b73val(Pr_>$2h5L{1s>O$m22CdTL$JN92B%_3$w9(Uq z^=A~d6yT8k9)nLpmD;7}V=RtqyFb4WX-mLXM#*|up)<9reM>{7?!|$sK5RMDEwfxx zzI7$i#L9E8;t_(sbrl3yC&$oVgES_*d9#?|InKQ>J+Yj&ey#DeI zcn7=#-U08xW;jr1D+%=Z|Ec8v|8EABufsdw9r#ZjQ1!XaTnEItv-KL8`m8;`-Hlsc z8dtK>6v4wB$0M5Kc>JPI4fo;J*ft&Yg`cx7mTbfuTz~za0XSz6e_zv_mZ8ru{Qkdk a8cTlvpDUkWC-3a}PA(ZG#+&;0`~Tm6_5pYR diff --git a/backend/contest/tests.py b/backend/contest/tests.py index 26a9bd28b..012c3087c 100644 --- a/backend/contest/tests.py +++ b/backend/contest/tests.py @@ -5,7 +5,9 @@ from utils.api.tests import APITestCase -from .models import ContestAnnouncement, ContestRuleType, Contest +from .models import ContestAnnouncement, ContestRuleType, Contest, ACMContestRank +from submission.models import Submission +from problem.models import Problem, ProblemIOMode DEFAULT_CONTEST_DATA = {"title": "test title", "description": "test description", "start_time": timezone.localtime(timezone.now()), @@ -15,6 +17,34 @@ "allowed_ip_ranges": [], "visible": True, "real_time_rank": True} +DEFAULT_PROBLEM_DATA = {"_id": "A-110", "title": "test", "description": "

test

", "input_description": "test", + "output_description": "test", "time_limit": 1000, "memory_limit": 256, "difficulty": "Level1", + "visible": True, "languages": ["C", "C++", "Java", "Python2"], "template": {}, + "samples": [{"input": "test", "output": "test"}], "spj": False, "spj_language": "C", + "spj_code": "", "spj_compile_ok": True, "test_case_id": "499b26290cc7994e0b497212e842ea85", + "test_case_score": [{"output_name": "1.out", "input_name": "1.in", "output_size": 0, + "stripped_output_md5": "d41d8cd98f00b204e9800998ecf8427e", + "input_size": 0, "score": 0}], + "io_mode": {"io_mode": ProblemIOMode.standard, "input": "input.txt", "output": "output.txt"}, + "share_submission": False, + "rule_type": "ACM", "hint": "

test

", "source": "test"} + +DEFAULT_SUBMISSION_DATA = { + "problem_id": "1", + "user_id": 1, + "username": "test", + "code": "xxxxxxxxxxxxxx", + "result": -2, + "info": {}, + "language": "C", + "statistic_info": {} +} + + +DEFAULT_ACMCONTESTRANK_DATA = {"submission_number": 1, "accepted_number": 1, "total_time": 123, "total_penalty": 123, + "submission_info": {"1": {"is_ac": True, "ac_time": 123, "penalty": 123, "problem_submission": 1}}, + "contest": 1} + class ContestAdminAPITest(APITestCase): def setUp(self): @@ -148,3 +178,36 @@ def test_get_contest_announcement_list(self): contest_id = self.create_contest_announcements() response = self.client.get(self.url, data={"contest_id": contest_id}) self.assertSuccess(response) + + +class UserContestAPITest(APITestCase): + def setUp(self): + # create contest + admin = self.create_admin() + self.contest = Contest.objects.create(created_by=admin, **DEFAULT_CONTEST_DATA) + + # create problem in contest + data = copy.deepcopy(DEFAULT_PROBLEM_DATA) + data["contest_id"] = self.contest.id + self.problem = Problem.objects.create(created_by=admin, **data) + + # user submit problem + user = self.create_user("test", "test123") + data = copy.deepcopy(DEFAULT_SUBMISSION_DATA) + data["contest_id"] = self.contest.id + data["problem_id"] = self.problem.id + data["user_id"] = user.id + self.submission = Submission.objects.create(**data) + + # create ACMContestRank + data = copy.deepcopy(DEFAULT_ACMCONTESTRANK_DATA) + data["user"] = user + data["contest"] = self.contest + self.rank = ACMContestRank.objects.create(**data) + + self.url = self.reverse("contest_user_api") + + # test UserContestAPI : can user get contest info which he participated and rank? + def test_get_participated_contest_list(self): + response = self.client.get(self.url) + self.assertSuccess(response) From 26489aa5b472551a1304a83744b4d83e05100b44 Mon Sep 17 00:00:00 2001 From: Jimin Ha Date: Fri, 25 Feb 2022 03:23:10 +0000 Subject: [PATCH 22/24] feat: add contestprize model --- backend/contest/models.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/backend/contest/models.py b/backend/contest/models.py index d6cbf9716..6f7b7e28c 100644 --- a/backend/contest/models.py +++ b/backend/contest/models.py @@ -13,6 +13,10 @@ class Contest(models.Model): title = models.TextField() description = RichTextField() + requirements = JSONField(default=list) + constraints = JSONField(default=list) + # allowed_groups = models.ManyToManyField(Group, blank=True) + scoring = models.TextField(default="ACM-ICPC style") # show real time rank or cached rank real_time_rank = models.BooleanField() password = models.TextField(null=True) @@ -57,10 +61,18 @@ class Meta: ordering = ("-start_time",) +class ContestPrize(models.Model): + contest = models.ForeignKey(Contest, on_delete=models.CASCADE) + color = models.TextField() + name = models.TextField() + reward = models.TextField() + + class AbstractContestRank(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) contest = models.ForeignKey(Contest, on_delete=models.CASCADE) submission_number = models.IntegerField(default=0) + prize = models.ForeignKey(ContestPrize, on_delete=models.SET_NULL, blank=True, null=True) class Meta: abstract = True From b7adf6895eb22142e719ab16e15cce5ffbf1e016 Mon Sep 17 00:00:00 2001 From: goo314 Date: Tue, 1 Mar 2022 13:54:54 +0000 Subject: [PATCH 23/24] style: Change code style --- backend/contest/tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/contest/tests.py b/backend/contest/tests.py index 012c3087c..42463584b 100644 --- a/backend/contest/tests.py +++ b/backend/contest/tests.py @@ -42,8 +42,8 @@ DEFAULT_ACMCONTESTRANK_DATA = {"submission_number": 1, "accepted_number": 1, "total_time": 123, "total_penalty": 123, - "submission_info": {"1": {"is_ac": True, "ac_time": 123, "penalty": 123, "problem_submission": 1}}, - "contest": 1} + "submission_info": {"1": {"is_ac": True, "ac_time": 123, "penalty": 123, "problem_submission": 1}}, + "contest": 1} class ContestAdminAPITest(APITestCase): From 03e7fe9349afabc661c330262866fa67937572c9 Mon Sep 17 00:00:00 2001 From: Jimin Ha Date: Wed, 2 Mar 2022 05:32:34 +0000 Subject: [PATCH 24/24] migrate model change --- .../migrations/0013_auto_20220302_1413.py | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 backend/contest/migrations/0013_auto_20220302_1413.py diff --git a/backend/contest/migrations/0013_auto_20220302_1413.py b/backend/contest/migrations/0013_auto_20220302_1413.py new file mode 100644 index 000000000..5727aedff --- /dev/null +++ b/backend/contest/migrations/0013_auto_20220302_1413.py @@ -0,0 +1,49 @@ +# Generated by Django 3.2.12 on 2022-03-02 05:13 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('contest', '0012_rename_total_score_acmcontestrank_total_penalty'), + ] + + operations = [ + migrations.AddField( + model_name='contest', + name='constraints', + field=models.JSONField(default=list), + ), + migrations.AddField( + model_name='contest', + name='requirements', + field=models.JSONField(default=list), + ), + migrations.AddField( + model_name='contest', + name='scoring', + field=models.TextField(default='ACM-ICPC style'), + ), + migrations.CreateModel( + name='ContestPrize', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('color', models.TextField()), + ('name', models.TextField()), + ('reward', models.TextField()), + ('contest', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contest.contest')), + ], + ), + migrations.AddField( + model_name='acmcontestrank', + name='prize', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='contest.contestprize'), + ), + migrations.AddField( + model_name='oicontestrank', + name='prize', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='contest.contestprize'), + ), + ]