From 991698bf2305c04430606fb8d8cd1ca24ca92a5f Mon Sep 17 00:00:00 2001 From: Jimin Ha Date: Sat, 8 Jan 2022 18:03:15 +0000 Subject: [PATCH 01/46] feat: Add and link user profile page --- frontend/src/pages/oj/components/Header.vue | 6 ++ frontend/src/pages/oj/router/routes.js | 13 +++- frontend/src/pages/oj/views/index.js | 4 +- frontend/src/pages/oj/views/user/Profile.vue | 82 ++++++++++++++++++++ 4 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 frontend/src/pages/oj/views/user/Profile.vue diff --git a/frontend/src/pages/oj/components/Header.vue b/frontend/src/pages/oj/components/Header.vue index 61ad0ff39..8a0dd5d5a 100644 --- a/frontend/src/pages/oj/components/Header.vue +++ b/frontend/src/pages/oj/components/Header.vue @@ -28,6 +28,7 @@ @@ -77,6 +78,11 @@ export default { } else { window.open('/admin/') } + }, + async goProfile () { + await this.$router.push({ + name: 'profile' + }) } }, computed: { diff --git a/frontend/src/pages/oj/router/routes.js b/frontend/src/pages/oj/router/routes.js index 3bccb2b51..c2b99e860 100644 --- a/frontend/src/pages/oj/router/routes.js +++ b/frontend/src/pages/oj/router/routes.js @@ -21,7 +21,8 @@ import { LectureAssignmentList, LectureAssignmentDetail, LectureQna, - LectureQnaDetail + LectureQnaDetail, + Profile } from '../views' export default [ @@ -116,9 +117,9 @@ export default [ meta: { title: 'Contest Ranking' } }, { - name: 'profile-setting', + name: 'setting', path: '/setting', - meta: { requiresAuth: true, title: 'Profile Settings' }, + meta: { requiresAuth: true, title: 'settings' }, component: ProfileSetting }, { @@ -163,6 +164,12 @@ export default [ meta: { title: 'Lecture QnA Detail' }, component: LectureQnaDetail }, + { + name: 'profile', + path: '/profile', + meta: { requiresAuth: true, title: 'My Profile' }, + component: Profile + }, { path: '*', meta: { title: '404' }, diff --git a/frontend/src/pages/oj/views/index.js b/frontend/src/pages/oj/views/index.js index 06f6554cb..5ba68ebbf 100644 --- a/frontend/src/pages/oj/views/index.js +++ b/frontend/src/pages/oj/views/index.js @@ -12,6 +12,7 @@ import LectureAssignmentList from './lecture/LectureAssignmentList.vue' import LectureAssignmentDetail from './lecture/LectureAssignmentDetail.vue' import LectureQna from './lecture/LectureQnA.vue' import LectureQnaDetail from './lecture/LectureQnADetail.vue' +import Profile from './user/Profile.vue' // Grouping Components in the Same Chunk const Problem = () => import(/* webpackChunkName: "Problem" */ '@oj/views/problem/Problem.vue') @@ -32,7 +33,8 @@ export { Logout, ProblemList, Announcement, AnnouncementList, Problem, ApplyResetPassword, ResetPassword, EmailAuth, ProfileSetting, ContestList, ContestDetail, ContestProblemList, ContestRanking, Register, - LectureList, LectureDashboard, LectureAssignmentList, LectureAssignmentDetail, LectureQna, LectureQnaDetail + LectureList, LectureDashboard, LectureAssignmentList, LectureAssignmentDetail, LectureQna, LectureQnaDetail, + Profile } /* 구성 요소 내보내기는 두 가지 범주로 나뉩니다. * 하나는 일반적으로 직접 내보내기에 사용되며 diff --git a/frontend/src/pages/oj/views/user/Profile.vue b/frontend/src/pages/oj/views/user/Profile.vue new file mode 100644 index 000000000..bd1b4cd7c --- /dev/null +++ b/frontend/src/pages/oj/views/user/Profile.vue @@ -0,0 +1,82 @@ + + + + + From 3e669bf6930d9dfe327bfc859f72903af0613775 Mon Sep 17 00:00:00 2001 From: Jimin Ha Date: Sun, 9 Jan 2022 03:39:21 +0000 Subject: [PATCH 02/46] feat: initialize user profile page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - User profile 페이지의 공통 부분과 탭을 만든다. --- .../oj/components/user/ProfileContest.vue | 38 ++++++++++ .../pages/oj/components/user/ProfileGroup.vue | 40 ++++++++++ .../oj/components/user/ProfileSubmission.vue | 40 ++++++++++ .../oj/components/user/TabSplitInTwo.vue | 60 +++++++++++++++ .../src/pages/oj/components/user/UserInfo.vue | 74 +++++++++++++++++++ frontend/src/pages/oj/views/user/Profile.vue | 14 ++-- 6 files changed, 261 insertions(+), 5 deletions(-) create mode 100644 frontend/src/pages/oj/components/user/ProfileContest.vue create mode 100644 frontend/src/pages/oj/components/user/ProfileGroup.vue create mode 100644 frontend/src/pages/oj/components/user/ProfileSubmission.vue create mode 100644 frontend/src/pages/oj/components/user/TabSplitInTwo.vue create mode 100644 frontend/src/pages/oj/components/user/UserInfo.vue diff --git a/frontend/src/pages/oj/components/user/ProfileContest.vue b/frontend/src/pages/oj/components/user/ProfileContest.vue new file mode 100644 index 000000000..1af2953b0 --- /dev/null +++ b/frontend/src/pages/oj/components/user/ProfileContest.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/frontend/src/pages/oj/components/user/ProfileGroup.vue b/frontend/src/pages/oj/components/user/ProfileGroup.vue new file mode 100644 index 000000000..c1cea032e --- /dev/null +++ b/frontend/src/pages/oj/components/user/ProfileGroup.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/frontend/src/pages/oj/components/user/ProfileSubmission.vue b/frontend/src/pages/oj/components/user/ProfileSubmission.vue new file mode 100644 index 000000000..2e13d44e4 --- /dev/null +++ b/frontend/src/pages/oj/components/user/ProfileSubmission.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/frontend/src/pages/oj/components/user/TabSplitInTwo.vue b/frontend/src/pages/oj/components/user/TabSplitInTwo.vue new file mode 100644 index 000000000..bf34aab5f --- /dev/null +++ b/frontend/src/pages/oj/components/user/TabSplitInTwo.vue @@ -0,0 +1,60 @@ + + + + + diff --git a/frontend/src/pages/oj/components/user/UserInfo.vue b/frontend/src/pages/oj/components/user/UserInfo.vue new file mode 100644 index 000000000..5d7f19cef --- /dev/null +++ b/frontend/src/pages/oj/components/user/UserInfo.vue @@ -0,0 +1,74 @@ + + + + + diff --git a/frontend/src/pages/oj/views/user/Profile.vue b/frontend/src/pages/oj/views/user/Profile.vue index bd1b4cd7c..c91662da9 100644 --- a/frontend/src/pages/oj/views/user/Profile.vue +++ b/frontend/src/pages/oj/views/user/Profile.vue @@ -8,6 +8,7 @@
+ @@ -21,17 +22,20 @@ From 821dd0d473d5bf80025a7d40a5f3d4474d28e8a5 Mon Sep 17 00:00:00 2001 From: DailyLinux Date: Tue, 1 Feb 2022 13:02:25 +0000 Subject: [PATCH 04/46] Change CSS. --- .../pages/oj/components/user/ProfileGroup.vue | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/frontend/src/pages/oj/components/user/ProfileGroup.vue b/frontend/src/pages/oj/components/user/ProfileGroup.vue index 11d6a1a6e..e532ce72d 100644 --- a/frontend/src/pages/oj/components/user/ProfileGroup.vue +++ b/frontend/src/pages/oj/components/user/ProfileGroup.vue @@ -42,13 +42,13 @@

Member

- {{ member }} - - @@ -145,8 +145,8 @@ export default { background-color: #8DC63F !important; border-color: transparent; border: none; - border-radius: 7px; - width: 6%; + border-radius: 10px; + padding: 2px 15px; } .group { display: flex; @@ -167,7 +167,7 @@ export default { display: flex; flex-direction: column; justify-items: center; - margin-left: 20px; + margin-left: 25px; } .group-name{ color: #173747; @@ -180,7 +180,7 @@ export default { margin-top: 5px; } #logo { - width: 89px; + width: 75px; height: 83px; margin-left: 20px; } @@ -224,6 +224,14 @@ export default { font-weight: bold; margin-block: 20px; } + .member { + min-width: 140px; + display: inline-flex; + justify-content: space-between; + align-content: space-between; + margin-right: 20px; + overflow: hidden + } .promote { background-color: #569BD8 !important; border-color: transparent; @@ -256,8 +264,8 @@ export default { background-color: #8DC63F !important; border-color: transparent; border: none; - border-radius: 7px; - width: 7%; + border-radius: 10px; + padding: 2px 15px; margin-inline: 10px; color: #FFFFFF; } @@ -265,8 +273,8 @@ export default { background-color: #FF6663 !important; border-color: transparent; border: none; - border-radius: 7px; - width: 7%; + border-radius: 10px; + padding: 2px 20px; margin-inline: 10px; color: #FFFFFF; } From 56d2011e862e4f96a639cbe4d158259e45e6932d Mon Sep 17 00:00:00 2001 From: Jimin Ha Date: Tue, 1 Feb 2022 13:58:31 +0000 Subject: [PATCH 05/46] change section title to common css MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 다른 프로필 탭과의 통일성을 위해 .section title css property 설정 --- .../pages/oj/components/user/ProfileGroup.vue | 21 +++++-------------- frontend/src/styles/common.scss | 2 +- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/frontend/src/pages/oj/components/user/ProfileGroup.vue b/frontend/src/pages/oj/components/user/ProfileGroup.vue index e532ce72d..f54f94b97 100644 --- a/frontend/src/pages/oj/components/user/ProfileGroup.vue +++ b/frontend/src/pages/oj/components/user/ProfileGroup.vue @@ -1,8 +1,8 @@ From 31cddcffdda8908c72d8fc646c312009527e9d3b Mon Sep 17 00:00:00 2001 From: goo314 Date: Fri, 28 Jan 2022 13:59:19 +0900 Subject: [PATCH 15/46] 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 90ef7c80ed4b61a2b6302f1a43ea9baa24b2673e Mon Sep 17 00:00:00 2001 From: goo314 Date: Fri, 28 Jan 2022 18:11:47 +0900 Subject: [PATCH 16/46] 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 d60dd19a8428f88dd0a2b7bb6e5c85ed5ece9d3b Mon Sep 17 00:00:00 2001 From: goo314 Date: Fri, 28 Jan 2022 18:53:59 +0900 Subject: [PATCH 17/46] 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 48c4bdc54f7996b709bfc34960e3221b58d8ea79 Mon Sep 17 00:00:00 2001 From: goo314 Date: Sat, 29 Jan 2022 01:58:21 +0900 Subject: [PATCH 18/46] 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 fedb98cb4b6115aa5ce422d935583ef64eb187aa Mon Sep 17 00:00:00 2001 From: goo314 Date: Sat, 29 Jan 2022 01:59:17 +0900 Subject: [PATCH 19/46] 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 2f2c8837a9a4cc909dd9c7f08a56cb14f5422009 Mon Sep 17 00:00:00 2001 From: goo314 Date: Sun, 6 Feb 2022 21:31:44 +0900 Subject: [PATCH 20/46] 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 953088014..5ca922348 100644 --- a/frontend/src/pages/oj/router/routes.js +++ b/frontend/src/pages/oj/router/routes.js @@ -168,7 +168,7 @@ export default [ { name: 'profile', path: '/profile', - meta: { title: 'My Profile' }, + meta: { requiresAuth: true, title: 'My Profile' }, component: Profile }, { From 0d9913199388721b0ef0f67af14f51646737b23f Mon Sep 17 00:00:00 2001 From: goo314 Date: Tue, 8 Feb 2022 12:23:05 +0000 Subject: [PATCH 21/46] 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 010714192..66d55f9ce 100644 --- a/backend/contest/serializers.py +++ b/backend/contest/serializers.py @@ -112,3 +112,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 4b1bad0fac5d02bac7119abb5d8903446e5dabcc Mon Sep 17 00:00:00 2001 From: goo314 Date: Wed, 9 Feb 2022 06:30:59 +0000 Subject: [PATCH 22/46] 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 66d55f9ce..815242f43 100644 --- a/backend/contest/serializers.py +++ b/backend/contest/serializers.py @@ -117,3 +117,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 679503c2eb83589aa076eb69fa9124e0138f0285 Mon Sep 17 00:00:00 2001 From: goo314 Date: Thu, 10 Feb 2022 04:27:27 +0000 Subject: [PATCH 23/46] 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 815242f43..3fa2e9e89 100644 --- a/backend/contest/serializers.py +++ b/backend/contest/serializers.py @@ -113,6 +113,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 56326a56f86078b75fefae0c174d3aca72356c3a Mon Sep 17 00:00:00 2001 From: goo314 Date: Thu, 10 Feb 2022 07:09:37 +0000 Subject: [PATCH 24/46] 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 d605b2c6c..6647ff417 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 4d10173a33a6d931423c5bf343a51cabf55f773f Mon Sep 17 00:00:00 2001 From: goo314 Date: Mon, 14 Feb 2022 23:47:33 +0900 Subject: [PATCH 25/46] 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 4c50f2290..dffe1db81 100644 --- a/frontend/src/pages/oj/api.js +++ b/frontend/src/pages/oj/api.js @@ -208,6 +208,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 1787bcb46a12d463dce35c88cb7ca832f768d86d Mon Sep 17 00:00:00 2001 From: goo314 Date: Sat, 26 Feb 2022 12:26:09 +0900 Subject: [PATCH 28/46] 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 c7f5a2e86..729b76444 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 from problem.models import ProblemIOMode @@ -29,6 +31,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): @@ -167,3 +197,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 bdf081e223c4d452cc4dd4a5307645ac7c43742e Mon Sep 17 00:00:00 2001 From: Jimin Ha Date: Fri, 25 Feb 2022 03:23:10 +0000 Subject: [PATCH 29/46] 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 6647ff417..2f8333bec 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 2b67eea242909dc6148cf1ecbdd3c59834969f34 Mon Sep 17 00:00:00 2001 From: goo314 Date: Tue, 1 Mar 2022 13:54:54 +0000 Subject: [PATCH 30/46] 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 729b76444..2b05d8a4a 100644 --- a/backend/contest/tests.py +++ b/backend/contest/tests.py @@ -56,8 +56,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 fa654148a0ad17c744f9df79a5be9a0162545915 Mon Sep 17 00:00:00 2001 From: Jimin Ha Date: Wed, 2 Mar 2022 05:32:34 +0000 Subject: [PATCH 31/46] 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'), + ), + ] From ead63b172809ec304f5ccd5ca570b07f6b0c3d04 Mon Sep 17 00:00:00 2001 From: Jimin Ha Date: Wed, 2 Mar 2022 06:37:37 +0000 Subject: [PATCH 32/46] resolve conflict: whiel rebase on master --- ...0302_1413.py => 0014_auto_20220302_1508.py} | 4 ++-- .../migrations/0015_submission_title.py | 18 ------------------ ...de_length.py => 0017_auto_20220302_1508.py} | 9 +++++++-- backend/submission/urls.py | 2 +- frontend/src/pages/oj/router/routes.js | 3 +-- frontend/src/pages/oj/views/index.js | 2 +- 6 files changed, 12 insertions(+), 26 deletions(-) rename backend/contest/migrations/{0013_auto_20220302_1413.py => 0014_auto_20220302_1508.py} (92%) delete mode 100644 backend/submission/migrations/0015_submission_title.py rename backend/submission/migrations/{0014_submission_code_length.py => 0017_auto_20220302_1508.py} (54%) diff --git a/backend/contest/migrations/0013_auto_20220302_1413.py b/backend/contest/migrations/0014_auto_20220302_1508.py similarity index 92% rename from backend/contest/migrations/0013_auto_20220302_1413.py rename to backend/contest/migrations/0014_auto_20220302_1508.py index 5727aedff..e77580b74 100644 --- a/backend/contest/migrations/0013_auto_20220302_1413.py +++ b/backend/contest/migrations/0014_auto_20220302_1508.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.12 on 2022-03-02 05:13 +# Generated by Django 3.2.12 on 2022-03-02 06:08 from django.db import migrations, models import django.db.models.deletion @@ -7,7 +7,7 @@ class Migration(migrations.Migration): dependencies = [ - ('contest', '0012_rename_total_score_acmcontestrank_total_penalty'), + ('contest', '0013_contestannouncement_problem'), ] operations = [ diff --git a/backend/submission/migrations/0015_submission_title.py b/backend/submission/migrations/0015_submission_title.py deleted file mode 100644 index d73d95187..000000000 --- a/backend/submission/migrations/0015_submission_title.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 3.2.12 on 2022-02-11 07:18 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('submission', '0014_submission_code_length'), - ] - - operations = [ - migrations.AddField( - model_name='submission', - name='title', - field=models.TextField(null=True), - ), - ] diff --git a/backend/submission/migrations/0014_submission_code_length.py b/backend/submission/migrations/0017_auto_20220302_1508.py similarity index 54% rename from backend/submission/migrations/0014_submission_code_length.py rename to backend/submission/migrations/0017_auto_20220302_1508.py index 5a0cc7eef..a4a912204 100644 --- a/backend/submission/migrations/0014_submission_code_length.py +++ b/backend/submission/migrations/0017_auto_20220302_1508.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.12 on 2022-02-10 10:37 +# Generated by Django 3.2.12 on 2022-03-02 06:08 from django.db import migrations, models @@ -6,7 +6,7 @@ class Migration(migrations.Migration): dependencies = [ - ('submission', '0013_auto_20211030_1535'), + ('submission', '0016_auto_20211226_1458'), ] operations = [ @@ -15,4 +15,9 @@ class Migration(migrations.Migration): name='code_length', field=models.IntegerField(default=0), ), + migrations.AddField( + model_name='submission', + name='title', + field=models.TextField(null=True), + ), ] diff --git a/backend/submission/urls.py b/backend/submission/urls.py index 6527232df..dd88cac4a 100644 --- a/backend/submission/urls.py +++ b/backend/submission/urls.py @@ -2,7 +2,7 @@ from .views import (SubmissionAPI, SubmissionListAPI, ContestSubmissionListAPI, AssignmentSubmissionListAPI, AssignmentSubmissionListProfessorAPI, SubmissionExistsAPI, EditSubmissionScoreAPI) -from .views import ProfileSubmissionListAPI, SubmissionAPI, SubmissionListAPI, ContestSubmissionListAPI, SubmissionExistsAPI +from .views import ProfileSubmissionListAPI urlpatterns = [ path("submission/", SubmissionAPI.as_view(), name="submission_api"), diff --git a/frontend/src/pages/oj/router/routes.js b/frontend/src/pages/oj/router/routes.js index 5ca922348..c2b99e860 100644 --- a/frontend/src/pages/oj/router/routes.js +++ b/frontend/src/pages/oj/router/routes.js @@ -22,8 +22,7 @@ import { LectureAssignmentDetail, LectureQna, LectureQnaDetail, - Profile, - ProfileContest + Profile } from '../views' export default [ diff --git a/frontend/src/pages/oj/views/index.js b/frontend/src/pages/oj/views/index.js index 2074b4e6f..5ba68ebbf 100644 --- a/frontend/src/pages/oj/views/index.js +++ b/frontend/src/pages/oj/views/index.js @@ -34,7 +34,7 @@ export { ApplyResetPassword, ResetPassword, EmailAuth, ProfileSetting, ContestList, ContestDetail, ContestProblemList, ContestRanking, Register, LectureList, LectureDashboard, LectureAssignmentList, LectureAssignmentDetail, LectureQna, LectureQnaDetail, - Profile, ProfileContest + Profile } /* 구성 요소 내보내기는 두 가지 범주로 나뉩니다. * 하나는 일반적으로 직접 내보내기에 사용되며 From bc3dff8c32b70194ac86eb5ef07bb8ca0d222724 Mon Sep 17 00:00:00 2001 From: Jimin Ha Date: Wed, 2 Mar 2022 06:38:04 +0000 Subject: [PATCH 33/46] Fix UserContestAPITest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Problem Tag을 제대로 사용하여 테스트 코드를 작성한다. --- backend/contest/tests.py | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/backend/contest/tests.py b/backend/contest/tests.py index 2b05d8a4a..099adfdbd 100644 --- a/backend/contest/tests.py +++ b/backend/contest/tests.py @@ -7,9 +7,7 @@ from .models import ContestAnnouncement, ContestRuleType, Contest, ACMContestRank from submission.models import Submission -from problem.models import Problem, ProblemIOMode - -from problem.models import ProblemIOMode +from problem.models import Problem, ProblemIOMode, ProblemTag DEFAULT_PROBLEM_DATA = {"_id": "A-110", "title": "test", "description": "

test

", "input_description": "test", "output_description": "test", "time_limit": 1000, "memory_limit": 256, "difficulty": "Level1", @@ -31,18 +29,6 @@ "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, @@ -208,8 +194,17 @@ def setUp(self): # 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) + tags = data.pop("tags") + problem = Problem.objects.create(created_by=admin, **data) + + for item in tags: + try: + tag = ProblemTag.objects.get(name=item) + except ProblemTag.DoesNotExist: + tag = ProblemTag.objects.create(name=item) + problem.tags.add(tag) + self.problem = problem # user submit problem user = self.create_user("test", "test123") data = copy.deepcopy(DEFAULT_SUBMISSION_DATA) From 7dd4222079c14475e8e5b4c446f266fd1284ed80 Mon Sep 17 00:00:00 2001 From: Jimin Ha Date: Wed, 2 Mar 2022 06:47:02 +0000 Subject: [PATCH 34/46] minor design change followed by tailwind css MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - tailwind css로 도입으로 깨진 디자인들을 복구한다. --- frontend/src/pages/oj/components/user/ProfileSubmission.vue | 1 + frontend/src/pages/oj/components/user/TabSplitInTwo.vue | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/oj/components/user/ProfileSubmission.vue b/frontend/src/pages/oj/components/user/ProfileSubmission.vue index 813a06eb5..1038a6eaf 100644 --- a/frontend/src/pages/oj/components/user/ProfileSubmission.vue +++ b/frontend/src/pages/oj/components/user/ProfileSubmission.vue @@ -270,6 +270,7 @@ export default { display:inline; position:relative; top:36px; + font-size: 2rem; } .submission-list-card{ margin:0 auto; diff --git a/frontend/src/pages/oj/components/user/TabSplitInTwo.vue b/frontend/src/pages/oj/components/user/TabSplitInTwo.vue index bf34aab5f..f24a6efc8 100644 --- a/frontend/src/pages/oj/components/user/TabSplitInTwo.vue +++ b/frontend/src/pages/oj/components/user/TabSplitInTwo.vue @@ -44,7 +44,7 @@ export default { .tab-split-in-two { display: flex; justify-content: space-between; - margin: 0px 50px; + margin: 10px 50px; overflow: auto; .tab-split-in-two__tab { margin: 0px 10px; From 1933ea56f2454148ee9d9e99ba924ab7eaeb16af Mon Sep 17 00:00:00 2001 From: st42597 Date: Tue, 15 Mar 2022 11:00:10 +0000 Subject: [PATCH 35/46] init: temperature --- backend/oj/settings.py | 1 + backend/oj/urls.py | 1 + backend/temperature/__init__.py | 0 backend/temperature/admin.py | 3 ++ backend/temperature/apps.py | 6 +++ .../temperature/migrations/0001_initial.py | 38 +++++++++++++++ .../migrations/0002_auto_20220315_1749.py | 22 +++++++++ backend/temperature/migrations/__init__.py | 0 backend/temperature/models.py | 46 +++++++++++++++++++ backend/temperature/serializers.py | 6 +++ backend/temperature/tests.py | 3 ++ backend/temperature/urls.py | 7 +++ backend/temperature/views.py | 40 ++++++++++++++++ 13 files changed, 173 insertions(+) create mode 100644 backend/temperature/__init__.py create mode 100644 backend/temperature/admin.py create mode 100644 backend/temperature/apps.py create mode 100644 backend/temperature/migrations/0001_initial.py create mode 100644 backend/temperature/migrations/0002_auto_20220315_1749.py create mode 100644 backend/temperature/migrations/__init__.py create mode 100644 backend/temperature/models.py create mode 100644 backend/temperature/serializers.py create mode 100644 backend/temperature/tests.py create mode 100644 backend/temperature/urls.py create mode 100644 backend/temperature/views.py diff --git a/backend/oj/settings.py b/backend/oj/settings.py index 5ccec1c56..11154a0a2 100644 --- a/backend/oj/settings.py +++ b/backend/oj/settings.py @@ -45,6 +45,7 @@ 'contest', 'utils', 'submission', + 'temperature', 'options', 'judge', 'assignment', diff --git a/backend/oj/urls.py b/backend/oj/urls.py index 1b5b9f61a..e37b147c0 100644 --- a/backend/oj/urls.py +++ b/backend/oj/urls.py @@ -25,4 +25,5 @@ path("api/lecture/professor/", include("course.urls.professor")), path("api/lecture/", include("assignment.urls.student")), path("api/lecture/professor/", include("assignment.urls.professor")), + path("api/", include("temperature.urls")), ] diff --git a/backend/temperature/__init__.py b/backend/temperature/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/temperature/admin.py b/backend/temperature/admin.py new file mode 100644 index 000000000..8c38f3f3d --- /dev/null +++ b/backend/temperature/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/backend/temperature/apps.py b/backend/temperature/apps.py new file mode 100644 index 000000000..120c14451 --- /dev/null +++ b/backend/temperature/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class TemperatureConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'temperature' diff --git a/backend/temperature/migrations/0001_initial.py b/backend/temperature/migrations/0001_initial.py new file mode 100644 index 000000000..8f5dbab41 --- /dev/null +++ b/backend/temperature/migrations/0001_initial.py @@ -0,0 +1,38 @@ +# Generated by Django 3.2.10 on 2022-03-15 07:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='SolvedProblem', + fields=[ + ('user_id', models.IntegerField(db_index=True)), + ('id', models.TextField(db_index=True, primary_key=True, serialize=False)), + ('score', models.IntegerField()), + ('solved_time', models.DateTimeField(auto_now_add=True)), + ], + options={ + 'db_table': 'solvedproblem', + }, + ), + migrations.CreateModel( + name='Temperature', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('user_id', models.IntegerField(unique=True)), + ('temeperature', models.IntegerField(default=0)), + ], + options={ + 'db_table': 'temperature', + 'ordering': ('-temeperature',), + }, + ), + ] diff --git a/backend/temperature/migrations/0002_auto_20220315_1749.py b/backend/temperature/migrations/0002_auto_20220315_1749.py new file mode 100644 index 000000000..c64bda673 --- /dev/null +++ b/backend/temperature/migrations/0002_auto_20220315_1749.py @@ -0,0 +1,22 @@ +# Generated by Django 3.2.10 on 2022-03-15 08:49 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('temperature', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='temperature', + options={'ordering': ('-temperature',)}, + ), + migrations.RenameField( + model_name='temperature', + old_name='temeperature', + new_name='temperature', + ), + ] diff --git a/backend/temperature/migrations/__init__.py b/backend/temperature/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/temperature/models.py b/backend/temperature/models.py new file mode 100644 index 000000000..b13aa0f84 --- /dev/null +++ b/backend/temperature/models.py @@ -0,0 +1,46 @@ +from django.db import models + + +class JudgeStatus: + COMPILE_ERROR = -2 + WRONG_ANSWER = -1 + ACCEPTED = 0 + CPU_TIME_LIMIT_EXCEEDED = 1 + REAL_TIME_LIMIT_EXCEEDED = 2 + MEMORY_LIMIT_EXCEEDED = 3 + RUNTIME_ERROR = 4 + SYSTEM_ERROR = 5 + PENDING = 6 + JUDGING = 7 + PARTIALLY_ACCEPTED = 8 + + +class ProblemScore: + scores = { + "LEVEL1": 8, + "LEVEL2": 16, + "LEVEL3": 32, + "LEVEL4": 64, + "LEVEL5": 128, + "LEVEL6": 256, + "LEVEL7": 512, + } + + +class Temperature(models.Model): + user_id = models.IntegerField(unique=True) + temperature = models.IntegerField(default=0) + + class Meta: + db_table = "temperature" + ordering = ("-temperature",) + + +class SolvedProblem(models.Model): + user_id = models.IntegerField(db_index=True) + id = models.TextField(primary_key=True, db_index=True) + score = models.IntegerField() + solved_time = models.DateTimeField(auto_now_add=True) + + class Meta: + db_table = "solvedproblem" diff --git a/backend/temperature/serializers.py b/backend/temperature/serializers.py new file mode 100644 index 000000000..3d198c5b4 --- /dev/null +++ b/backend/temperature/serializers.py @@ -0,0 +1,6 @@ +from utils.api import serializers + + +class CreateTemperatureSerializer(serializers.Serializer): + id = serializers.CharField() + difficulty = serializers.CharField() diff --git a/backend/temperature/tests.py b/backend/temperature/tests.py new file mode 100644 index 000000000..7ce503c2d --- /dev/null +++ b/backend/temperature/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/backend/temperature/urls.py b/backend/temperature/urls.py new file mode 100644 index 000000000..fd4e508c9 --- /dev/null +++ b/backend/temperature/urls.py @@ -0,0 +1,7 @@ +from django.urls import path + +from .views import TemperatureAPI + +urlpatterns = [ + path("temperature/", TemperatureAPI.as_view(), name="temperature_api") +] diff --git a/backend/temperature/views.py b/backend/temperature/views.py new file mode 100644 index 000000000..d898b3eaf --- /dev/null +++ b/backend/temperature/views.py @@ -0,0 +1,40 @@ +from utils.api import APIView, validate_serializer +from .models import ProblemScore, Temperature, SolvedProblem +from .serializers import CreateTemperatureSerializer + + +class TemperatureAPI(APIView): + @validate_serializer(CreateTemperatureSerializer) + def post(self, request): + id = request.data.get("id") + difficulty = request.data.get("difficulty") + if not id: + return self.error("Parameter error, id is required") + if not difficulty: + return self.error("Parameter error, difficulty is required") + user_temp = Temperature.objects.get(user_id=request.user.id) + user_temp_qs = Temperature.objects.filter(user_id=request.user.id) + if not user_temp: + Temperature.objects.create(user_id=request.user.id, temperature=0) + solved_problem = SolvedProblem.objects.filter(user_id=request.user.id, id=id) + if not solved_problem: + SolvedProblem.objects.create(user_id=request.user.id, + id=id, + score=ProblemScore.scores[difficulty]) + user_temp_qs.update(temperature=user_temp.temperature+ProblemScore.scores[difficulty]) + return self.success() + + def get(self, request): + user_temp = Temperature.objects.get(user_id=request.user.id) + if not user_temp: + data = "DB error, Data doesn't exist" + data = { + "temperature": user_temp.temperature + } + return self.success(data) + + +class RankAPI(APIView): + def get(self, request): + data = "123" + return self.success(data) From 6ee2690b910487ce1902f620391df2a42fed4aca Mon Sep 17 00:00:00 2001 From: st42597 Date: Tue, 15 Mar 2022 12:29:10 +0000 Subject: [PATCH 36/46] fix: minor fix & add: rankAPI --- .../migrations/0003_auto_20220315_2022.py | 24 +++++++++++ .../migrations/0004_alter_temperature_date.py | 18 +++++++++ .../migrations/0005_auto_20220315_2047.py | 40 +++++++++++++++++++ .../migrations/0006_alter_solvedproblem_id.py | 19 +++++++++ backend/temperature/models.py | 12 ++++-- backend/temperature/urls.py | 5 ++- backend/temperature/views.py | 23 +++++++---- 7 files changed, 129 insertions(+), 12 deletions(-) create mode 100644 backend/temperature/migrations/0003_auto_20220315_2022.py create mode 100644 backend/temperature/migrations/0004_alter_temperature_date.py create mode 100644 backend/temperature/migrations/0005_auto_20220315_2047.py create mode 100644 backend/temperature/migrations/0006_alter_solvedproblem_id.py diff --git a/backend/temperature/migrations/0003_auto_20220315_2022.py b/backend/temperature/migrations/0003_auto_20220315_2022.py new file mode 100644 index 000000000..76cf7eb34 --- /dev/null +++ b/backend/temperature/migrations/0003_auto_20220315_2022.py @@ -0,0 +1,24 @@ +# Generated by Django 3.2.10 on 2022-03-15 11:22 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('temperature', '0002_auto_20220315_1749'), + ] + + operations = [ + migrations.AddField( + model_name='temperature', + name='date', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + migrations.AlterUniqueTogether( + name='temperature', + unique_together={('user_id', 'date')}, + ), + ] diff --git a/backend/temperature/migrations/0004_alter_temperature_date.py b/backend/temperature/migrations/0004_alter_temperature_date.py new file mode 100644 index 000000000..2d4fbb7b5 --- /dev/null +++ b/backend/temperature/migrations/0004_alter_temperature_date.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.10 on 2022-03-15 11:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('temperature', '0003_auto_20220315_2022'), + ] + + operations = [ + migrations.AlterField( + model_name='temperature', + name='date', + field=models.DateField(auto_now_add=True), + ), + ] diff --git a/backend/temperature/migrations/0005_auto_20220315_2047.py b/backend/temperature/migrations/0005_auto_20220315_2047.py new file mode 100644 index 000000000..475ed8fc8 --- /dev/null +++ b/backend/temperature/migrations/0005_auto_20220315_2047.py @@ -0,0 +1,40 @@ +# Generated by Django 3.2.10 on 2022-03-15 11:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('temperature', '0004_alter_temperature_date'), + ] + + operations = [ + migrations.AlterModelOptions( + name='solvedproblem', + options={'ordering': ('-solved_time',)}, + ), + migrations.AlterModelOptions( + name='temperature', + options={'ordering': ('-date',)}, + ), + migrations.AddField( + model_name='solvedproblem', + name='_id', + field=models.TextField(db_index=True, default=0), + ), + migrations.AlterField( + model_name='solvedproblem', + name='id', + field=models.TextField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='solvedproblem', + name='solved_time', + field=models.DateField(auto_now_add=True), + ), + migrations.AlterUniqueTogether( + name='solvedproblem', + unique_together={('user_id', '_id')}, + ), + ] diff --git a/backend/temperature/migrations/0006_alter_solvedproblem_id.py b/backend/temperature/migrations/0006_alter_solvedproblem_id.py new file mode 100644 index 000000000..8c75f7537 --- /dev/null +++ b/backend/temperature/migrations/0006_alter_solvedproblem_id.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.10 on 2022-03-15 12:18 + +from django.db import migrations, models +import utils.shortcuts + + +class Migration(migrations.Migration): + + dependencies = [ + ('temperature', '0005_auto_20220315_2047'), + ] + + operations = [ + migrations.AlterField( + model_name='solvedproblem', + name='id', + field=models.TextField(db_index=True, default=utils.shortcuts.rand_str, primary_key=True, serialize=False), + ), + ] diff --git a/backend/temperature/models.py b/backend/temperature/models.py index b13aa0f84..b9f548b2d 100644 --- a/backend/temperature/models.py +++ b/backend/temperature/models.py @@ -1,4 +1,5 @@ from django.db import models +from utils.shortcuts import rand_str class JudgeStatus: @@ -30,17 +31,22 @@ class ProblemScore: class Temperature(models.Model): user_id = models.IntegerField(unique=True) temperature = models.IntegerField(default=0) + date = models.DateField(auto_now_add=True) class Meta: db_table = "temperature" - ordering = ("-temperature",) + unique_together = (("user_id", "date"),) + ordering = ("-date",) class SolvedProblem(models.Model): + id = models.TextField(default=rand_str, primary_key=True, db_index=True) user_id = models.IntegerField(db_index=True) - id = models.TextField(primary_key=True, db_index=True) + _id = models.TextField(db_index=True, default=0) score = models.IntegerField() - solved_time = models.DateTimeField(auto_now_add=True) + solved_time = models.DateField(auto_now_add=True) class Meta: db_table = "solvedproblem" + unique_together = (("user_id", "_id"),) + ordering = ("-solved_time",) diff --git a/backend/temperature/urls.py b/backend/temperature/urls.py index fd4e508c9..8703f523c 100644 --- a/backend/temperature/urls.py +++ b/backend/temperature/urls.py @@ -1,7 +1,8 @@ from django.urls import path -from .views import TemperatureAPI +from .views import TemperatureAPI, RankAPI urlpatterns = [ - path("temperature/", TemperatureAPI.as_view(), name="temperature_api") + path("temperature/", TemperatureAPI.as_view(), name="temperature_api"), + path("rank/", RankAPI.as_view(), name="rank_api") ] diff --git a/backend/temperature/views.py b/backend/temperature/views.py index d898b3eaf..bde89c3b8 100644 --- a/backend/temperature/views.py +++ b/backend/temperature/views.py @@ -1,6 +1,7 @@ from utils.api import APIView, validate_serializer from .models import ProblemScore, Temperature, SolvedProblem from .serializers import CreateTemperatureSerializer +import datetime class TemperatureAPI(APIView): @@ -12,14 +13,15 @@ def post(self, request): return self.error("Parameter error, id is required") if not difficulty: return self.error("Parameter error, difficulty is required") - user_temp = Temperature.objects.get(user_id=request.user.id) - user_temp_qs = Temperature.objects.filter(user_id=request.user.id) - if not user_temp: - Temperature.objects.create(user_id=request.user.id, temperature=0) - solved_problem = SolvedProblem.objects.filter(user_id=request.user.id, id=id) + date = datetime.date.today() + if not Temperature.objects.filter(user_id=request.user.id, date=date): + Temperature.objects.create(user_id=request.user.id) + user_temp = Temperature.objects.get(user_id=request.user.id, date=date) + user_temp_qs = Temperature.objects.filter(user_id=request.user.id, date=date) + solved_problem = SolvedProblem.objects.filter(user_id=request.user.id, _id=id) if not solved_problem: SolvedProblem.objects.create(user_id=request.user.id, - id=id, + _id=id, score=ProblemScore.scores[difficulty]) user_temp_qs.update(temperature=user_temp.temperature+ProblemScore.scores[difficulty]) return self.success() @@ -36,5 +38,12 @@ def get(self, request): class RankAPI(APIView): def get(self, request): - data = "123" + date = datetime.date.today() + for idx, temp in enumerate(list(Temperature.objects.filter(date=date).order_by("-temperature"))): + if temp.user_id == request.user.id: + rank = idx + 1 + break + data = { + "rank": rank + } return self.success(data) From 51f9849c32a0a6598e01397d5a91c586c414d799 Mon Sep 17 00:00:00 2001 From: st42597 Date: Wed, 23 Mar 2022 08:53:41 +0000 Subject: [PATCH 37/46] fix: foreign key --- backend/temperature/models.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/temperature/models.py b/backend/temperature/models.py index b9f548b2d..887c1e4a4 100644 --- a/backend/temperature/models.py +++ b/backend/temperature/models.py @@ -1,5 +1,6 @@ from django.db import models -from utils.shortcuts import rand_str +from problem.models import Problem +from account.models import User class JudgeStatus: @@ -29,24 +30,23 @@ class ProblemScore: class Temperature(models.Model): - user_id = models.IntegerField(unique=True) + user = models.ForeignKey(User, null=True, on_delete=models.CASCADE) temperature = models.IntegerField(default=0) date = models.DateField(auto_now_add=True) class Meta: db_table = "temperature" - unique_together = (("user_id", "date"),) + unique_together = (("user", "date"),) ordering = ("-date",) class SolvedProblem(models.Model): - id = models.TextField(default=rand_str, primary_key=True, db_index=True) - user_id = models.IntegerField(db_index=True) - _id = models.TextField(db_index=True, default=0) + user = models.ForeignKey(User, null=True, on_delete=models.CASCADE) + problem = models.ForeignKey(Problem, null=True, on_delete=models.CASCADE) score = models.IntegerField() solved_time = models.DateField(auto_now_add=True) class Meta: db_table = "solvedproblem" - unique_together = (("user_id", "_id"),) + unique_together = (("user", "problem"),) ordering = ("-solved_time",) From 067f9495e815a47b151e2fe69222bb30bdf3df29 Mon Sep 17 00:00:00 2001 From: st42597 Date: Wed, 23 Mar 2022 09:06:56 +0000 Subject: [PATCH 38/46] add: model migration --- .../migrations/0007_auto_20220323_1806.py | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 backend/temperature/migrations/0007_auto_20220323_1806.py diff --git a/backend/temperature/migrations/0007_auto_20220323_1806.py b/backend/temperature/migrations/0007_auto_20220323_1806.py new file mode 100644 index 000000000..35988561e --- /dev/null +++ b/backend/temperature/migrations/0007_auto_20220323_1806.py @@ -0,0 +1,57 @@ +# Generated by Django 3.2.10 on 2022-03-23 09:06 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('problem', '0015_auto_20211030_1535'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('temperature', '0006_alter_solvedproblem_id'), + ] + + operations = [ + migrations.AddField( + model_name='solvedproblem', + name='problem', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='problem.problem'), + ), + migrations.AddField( + model_name='solvedproblem', + name='user', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='temperature', + name='user', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AlterField( + model_name='solvedproblem', + name='id', + field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + migrations.AlterUniqueTogether( + name='solvedproblem', + unique_together={('user', 'problem')}, + ), + migrations.AlterUniqueTogether( + name='temperature', + unique_together={('user', 'date')}, + ), + migrations.RemoveField( + model_name='solvedproblem', + name='_id', + ), + migrations.RemoveField( + model_name='solvedproblem', + name='user_id', + ), + migrations.RemoveField( + model_name='temperature', + name='user_id', + ), + ] From fdaacb3671bc3df6c09bc12ec63226ba77571984 Mon Sep 17 00:00:00 2001 From: Jimin Ha Date: Wed, 23 Mar 2022 09:17:03 +0000 Subject: [PATCH 39/46] fix: remigrate temperature model changes --- .../temperature/migrations/0001_initial.py | 33 +++++++---- .../migrations/0002_auto_20220315_1749.py | 22 ------- .../migrations/0003_auto_20220315_2022.py | 24 -------- .../migrations/0004_alter_temperature_date.py | 18 ------ .../migrations/0005_auto_20220315_2047.py | 40 ------------- .../migrations/0006_alter_solvedproblem_id.py | 19 ------- .../migrations/0007_auto_20220323_1806.py | 57 ------------------- 7 files changed, 21 insertions(+), 192 deletions(-) delete mode 100644 backend/temperature/migrations/0002_auto_20220315_1749.py delete mode 100644 backend/temperature/migrations/0003_auto_20220315_2022.py delete mode 100644 backend/temperature/migrations/0004_alter_temperature_date.py delete mode 100644 backend/temperature/migrations/0005_auto_20220315_2047.py delete mode 100644 backend/temperature/migrations/0006_alter_solvedproblem_id.py delete mode 100644 backend/temperature/migrations/0007_auto_20220323_1806.py diff --git a/backend/temperature/migrations/0001_initial.py b/backend/temperature/migrations/0001_initial.py index 8f5dbab41..6c85433ed 100644 --- a/backend/temperature/migrations/0001_initial.py +++ b/backend/temperature/migrations/0001_initial.py @@ -1,6 +1,8 @@ -# Generated by Django 3.2.10 on 2022-03-15 07:17 +# Generated by Django 3.2.12 on 2022-03-23 09:15 +from django.conf import settings from django.db import migrations, models +import django.db.models.deletion class Migration(migrations.Migration): @@ -8,31 +10,38 @@ class Migration(migrations.Migration): initial = True dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('problem', '0018_auto_20211226_1458'), ] operations = [ migrations.CreateModel( - name='SolvedProblem', + name='Temperature', fields=[ - ('user_id', models.IntegerField(db_index=True)), - ('id', models.TextField(db_index=True, primary_key=True, serialize=False)), - ('score', models.IntegerField()), - ('solved_time', models.DateTimeField(auto_now_add=True)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('temperature', models.IntegerField(default=0)), + ('date', models.DateField(auto_now_add=True)), + ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], options={ - 'db_table': 'solvedproblem', + 'db_table': 'temperature', + 'ordering': ('-date',), + 'unique_together': {('user', 'date')}, }, ), migrations.CreateModel( - name='Temperature', + name='SolvedProblem', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('user_id', models.IntegerField(unique=True)), - ('temeperature', models.IntegerField(default=0)), + ('score', models.IntegerField()), + ('solved_time', models.DateField(auto_now_add=True)), + ('problem', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='problem.problem')), + ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], options={ - 'db_table': 'temperature', - 'ordering': ('-temeperature',), + 'db_table': 'solvedproblem', + 'ordering': ('-solved_time',), + 'unique_together': {('user', 'problem')}, }, ), ] diff --git a/backend/temperature/migrations/0002_auto_20220315_1749.py b/backend/temperature/migrations/0002_auto_20220315_1749.py deleted file mode 100644 index c64bda673..000000000 --- a/backend/temperature/migrations/0002_auto_20220315_1749.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 3.2.10 on 2022-03-15 08:49 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('temperature', '0001_initial'), - ] - - operations = [ - migrations.AlterModelOptions( - name='temperature', - options={'ordering': ('-temperature',)}, - ), - migrations.RenameField( - model_name='temperature', - old_name='temeperature', - new_name='temperature', - ), - ] diff --git a/backend/temperature/migrations/0003_auto_20220315_2022.py b/backend/temperature/migrations/0003_auto_20220315_2022.py deleted file mode 100644 index 76cf7eb34..000000000 --- a/backend/temperature/migrations/0003_auto_20220315_2022.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 3.2.10 on 2022-03-15 11:22 - -from django.db import migrations, models -import django.utils.timezone - - -class Migration(migrations.Migration): - - dependencies = [ - ('temperature', '0002_auto_20220315_1749'), - ] - - operations = [ - migrations.AddField( - model_name='temperature', - name='date', - field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), - preserve_default=False, - ), - migrations.AlterUniqueTogether( - name='temperature', - unique_together={('user_id', 'date')}, - ), - ] diff --git a/backend/temperature/migrations/0004_alter_temperature_date.py b/backend/temperature/migrations/0004_alter_temperature_date.py deleted file mode 100644 index 2d4fbb7b5..000000000 --- a/backend/temperature/migrations/0004_alter_temperature_date.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 3.2.10 on 2022-03-15 11:34 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('temperature', '0003_auto_20220315_2022'), - ] - - operations = [ - migrations.AlterField( - model_name='temperature', - name='date', - field=models.DateField(auto_now_add=True), - ), - ] diff --git a/backend/temperature/migrations/0005_auto_20220315_2047.py b/backend/temperature/migrations/0005_auto_20220315_2047.py deleted file mode 100644 index 475ed8fc8..000000000 --- a/backend/temperature/migrations/0005_auto_20220315_2047.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 3.2.10 on 2022-03-15 11:47 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('temperature', '0004_alter_temperature_date'), - ] - - operations = [ - migrations.AlterModelOptions( - name='solvedproblem', - options={'ordering': ('-solved_time',)}, - ), - migrations.AlterModelOptions( - name='temperature', - options={'ordering': ('-date',)}, - ), - migrations.AddField( - model_name='solvedproblem', - name='_id', - field=models.TextField(db_index=True, default=0), - ), - migrations.AlterField( - model_name='solvedproblem', - name='id', - field=models.TextField(primary_key=True, serialize=False), - ), - migrations.AlterField( - model_name='solvedproblem', - name='solved_time', - field=models.DateField(auto_now_add=True), - ), - migrations.AlterUniqueTogether( - name='solvedproblem', - unique_together={('user_id', '_id')}, - ), - ] diff --git a/backend/temperature/migrations/0006_alter_solvedproblem_id.py b/backend/temperature/migrations/0006_alter_solvedproblem_id.py deleted file mode 100644 index 8c75f7537..000000000 --- a/backend/temperature/migrations/0006_alter_solvedproblem_id.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 3.2.10 on 2022-03-15 12:18 - -from django.db import migrations, models -import utils.shortcuts - - -class Migration(migrations.Migration): - - dependencies = [ - ('temperature', '0005_auto_20220315_2047'), - ] - - operations = [ - migrations.AlterField( - model_name='solvedproblem', - name='id', - field=models.TextField(db_index=True, default=utils.shortcuts.rand_str, primary_key=True, serialize=False), - ), - ] diff --git a/backend/temperature/migrations/0007_auto_20220323_1806.py b/backend/temperature/migrations/0007_auto_20220323_1806.py deleted file mode 100644 index 35988561e..000000000 --- a/backend/temperature/migrations/0007_auto_20220323_1806.py +++ /dev/null @@ -1,57 +0,0 @@ -# Generated by Django 3.2.10 on 2022-03-23 09:06 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('problem', '0015_auto_20211030_1535'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('temperature', '0006_alter_solvedproblem_id'), - ] - - operations = [ - migrations.AddField( - model_name='solvedproblem', - name='problem', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='problem.problem'), - ), - migrations.AddField( - model_name='solvedproblem', - name='user', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='temperature', - name='user', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), - ), - migrations.AlterField( - model_name='solvedproblem', - name='id', - field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), - ), - migrations.AlterUniqueTogether( - name='solvedproblem', - unique_together={('user', 'problem')}, - ), - migrations.AlterUniqueTogether( - name='temperature', - unique_together={('user', 'date')}, - ), - migrations.RemoveField( - model_name='solvedproblem', - name='_id', - ), - migrations.RemoveField( - model_name='solvedproblem', - name='user_id', - ), - migrations.RemoveField( - model_name='temperature', - name='user_id', - ), - ] From 652369d698923d5e451a1375862b1f3448daa87c Mon Sep 17 00:00:00 2001 From: st42597 Date: Wed, 23 Mar 2022 18:23:00 +0900 Subject: [PATCH 40/46] fix: code style --- backend/temperature/admin.py | 3 --- backend/temperature/tests.py | 3 --- 2 files changed, 6 deletions(-) diff --git a/backend/temperature/admin.py b/backend/temperature/admin.py index 8c38f3f3d..e69de29bb 100644 --- a/backend/temperature/admin.py +++ b/backend/temperature/admin.py @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/backend/temperature/tests.py b/backend/temperature/tests.py index 7ce503c2d..e69de29bb 100644 --- a/backend/temperature/tests.py +++ b/backend/temperature/tests.py @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. From c1cbe399e127f666279b9d0ced5cf99d3ebbefc4 Mon Sep 17 00:00:00 2001 From: st42597 Date: Mon, 28 Mar 2022 07:44:27 +0000 Subject: [PATCH 41/46] init: history --- .../oj/components/user/ProfileHistory.vue | 128 ++++++++++++++++++ frontend/src/pages/oj/views/user/Profile.vue | 2 + 2 files changed, 130 insertions(+) create mode 100644 frontend/src/pages/oj/components/user/ProfileHistory.vue diff --git a/frontend/src/pages/oj/components/user/ProfileHistory.vue b/frontend/src/pages/oj/components/user/ProfileHistory.vue new file mode 100644 index 000000000..8a253d51a --- /dev/null +++ b/frontend/src/pages/oj/components/user/ProfileHistory.vue @@ -0,0 +1,128 @@ + + + + + + diff --git a/frontend/src/pages/oj/views/user/Profile.vue b/frontend/src/pages/oj/views/user/Profile.vue index c91662da9..9053a8202 100644 --- a/frontend/src/pages/oj/views/user/Profile.vue +++ b/frontend/src/pages/oj/views/user/Profile.vue @@ -25,6 +25,7 @@ import UserInfo from '../../components/user/UserInfo' import TabSplitInTwo from '../../components/user/TabSplitInTwo.vue' import ProfileSubmission from '../../components/user/ProfileSubmission.vue' +import ProfileHistory from '../../components/user/ProfileHistory.vue' import ProfileContest from '../../components/user/ProfileContest.vue' import ProfileGroup from '../../components/user/ProfileGroup.vue' @@ -34,6 +35,7 @@ export default { UserInfo, TabSplitInTwo, ProfileSubmission, + ProfileHistory, ProfileContest, ProfileGroup }, From c47a7b4e9243578febe6947c636aa0733a778dfa Mon Sep 17 00:00:00 2001 From: st42597 Date: Wed, 20 Apr 2022 12:31:29 +0000 Subject: [PATCH 42/46] fix: temperature --- backend/temperature/models.py | 17 +++++------ backend/temperature/serializers.py | 1 - backend/temperature/urls.py | 7 +++-- backend/temperature/views.py | 49 +++++++++++++++++++----------- 4 files changed, 44 insertions(+), 30 deletions(-) diff --git a/backend/temperature/models.py b/backend/temperature/models.py index 887c1e4a4..713f1cab4 100644 --- a/backend/temperature/models.py +++ b/backend/temperature/models.py @@ -19,13 +19,13 @@ class JudgeStatus: class ProblemScore: scores = { - "LEVEL1": 8, - "LEVEL2": 16, - "LEVEL3": 32, - "LEVEL4": 64, - "LEVEL5": 128, - "LEVEL6": 256, - "LEVEL7": 512, + "Level1": 8, + "Level2": 16, + "Level3": 32, + "Level4": 64, + "Level5": 128, + "Level6": 256, + "Level7": 512, } @@ -37,13 +37,12 @@ class Temperature(models.Model): class Meta: db_table = "temperature" unique_together = (("user", "date"),) - ordering = ("-date",) + ordering = ["-date", "-temperature"] class SolvedProblem(models.Model): user = models.ForeignKey(User, null=True, on_delete=models.CASCADE) problem = models.ForeignKey(Problem, null=True, on_delete=models.CASCADE) - score = models.IntegerField() solved_time = models.DateField(auto_now_add=True) class Meta: diff --git a/backend/temperature/serializers.py b/backend/temperature/serializers.py index 3d198c5b4..307502be2 100644 --- a/backend/temperature/serializers.py +++ b/backend/temperature/serializers.py @@ -3,4 +3,3 @@ class CreateTemperatureSerializer(serializers.Serializer): id = serializers.CharField() - difficulty = serializers.CharField() diff --git a/backend/temperature/urls.py b/backend/temperature/urls.py index 8703f523c..37c2378b3 100644 --- a/backend/temperature/urls.py +++ b/backend/temperature/urls.py @@ -1,8 +1,11 @@ from django.urls import path -from .views import TemperatureAPI, RankAPI +from .views import TemperatureAPI, RankAPI, TemperatureListAPI, SolvedProblemListAPI, RankListAPI urlpatterns = [ path("temperature/", TemperatureAPI.as_view(), name="temperature_api"), - path("rank/", RankAPI.as_view(), name="rank_api") + path("rank/", RankAPI.as_view(), name="rank_api"), + path("profile_temperatures/", TemperatureListAPI.as_view(), name="profile_temperature_list_api"), + path("profile_solvedproblems/", SolvedProblemListAPI.as_view(), name="profile_solvedproblems_list_api"), + path("profile_ranks/", RankListAPI.as_view(), name="profile_rank_list_api") ] diff --git a/backend/temperature/views.py b/backend/temperature/views.py index bde89c3b8..84a3eee47 100644 --- a/backend/temperature/views.py +++ b/backend/temperature/views.py @@ -1,41 +1,38 @@ from utils.api import APIView, validate_serializer from .models import ProblemScore, Temperature, SolvedProblem +from problem.models import Problem +from account.models import User from .serializers import CreateTemperatureSerializer import datetime class TemperatureAPI(APIView): - @validate_serializer(CreateTemperatureSerializer) def post(self, request): - id = request.data.get("id") - difficulty = request.data.get("difficulty") + id = request.GET.get("id") if not id: return self.error("Parameter error, id is required") - if not difficulty: - return self.error("Parameter error, difficulty is required") + difficulty = Problem.objects.get(id=id).difficulty + print(ProblemScore.scores[difficulty]) date = datetime.date.today() - if not Temperature.objects.filter(user_id=request.user.id, date=date): - Temperature.objects.create(user_id=request.user.id) - user_temp = Temperature.objects.get(user_id=request.user.id, date=date) - user_temp_qs = Temperature.objects.filter(user_id=request.user.id, date=date) - solved_problem = SolvedProblem.objects.filter(user_id=request.user.id, _id=id) + if not Temperature.objects.filter(user=request.user, date=date): + Temperature.objects.create(user=request.user) + user_temp = Temperature.objects.get(user=request.user, date=date) + user_temp_qs = Temperature.objects.filter(user=request.user, date=date) + solved_problem = SolvedProblem.objects.filter(user=request.user, problem=id) if not solved_problem: - SolvedProblem.objects.create(user_id=request.user.id, - _id=id, - score=ProblemScore.scores[difficulty]) + SolvedProblem.objects.create(user=request.user, + problem=Problem.objects.get(id=id)) user_temp_qs.update(temperature=user_temp.temperature+ProblemScore.scores[difficulty]) return self.success() def get(self, request): - user_temp = Temperature.objects.get(user_id=request.user.id) + date = datetime.date.today() + user_temp = Temperature.objects.get(user=request.user, date=date) if not user_temp: data = "DB error, Data doesn't exist" - data = { - "temperature": user_temp.temperature - } + else: data = { "temperature": user_temp.temperature } return self.success(data) - class RankAPI(APIView): def get(self, request): date = datetime.date.today() @@ -47,3 +44,19 @@ def get(self, request): "rank": rank } return self.success(data) +class TemperatureListAPI(APIView): + def get(self, request): + user_temps = Temperature.objects.get(user=request.user) + data = user_temps + return self.success(data) + +class SolvedProblemListAPI(APIView): + def get(self, request): + solved_problems = SolvedProblem.objects.filter(user_id=request.user.id) + data = solved_problems + return self.success(data) +class RankListAPI(APIView): + def get(self, request): + user_temps = Temperature.objects.__annotations__ + data = [] + return self.success(data) From e19539a76f7735389b24fdf62ddb031ee4590c79 Mon Sep 17 00:00:00 2001 From: st42597 Date: Wed, 20 Apr 2022 12:32:54 +0000 Subject: [PATCH 43/46] add: temperature api --- frontend/src/pages/oj/api.js | 10 ++++++++++ frontend/src/pages/oj/views/problem/Problem.vue | 9 ++++++++- frontend/src/pages/oj/views/user/Profile.vue | 11 ++++++++--- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/frontend/src/pages/oj/api.js b/frontend/src/pages/oj/api.js index 96cfa6545..8715162c4 100644 --- a/frontend/src/pages/oj/api.js +++ b/frontend/src/pages/oj/api.js @@ -328,6 +328,16 @@ export default { return ajax('assignment_submissions/', 'get', { params }) + }, + temperature (problemID) { + return ajax('temperature/', 'post', { + params: { + id: problemID + } + }) + }, + getTemperature () { + return ajax('temperature/', 'get') } } diff --git a/frontend/src/pages/oj/views/problem/Problem.vue b/frontend/src/pages/oj/views/problem/Problem.vue index dec066679..1c981d35c 100644 --- a/frontend/src/pages/oj/views/problem/Problem.vue +++ b/frontend/src/pages/oj/views/problem/Problem.vue @@ -391,7 +391,10 @@ export default { theme: 'material', theme_list: ['solarized', 'monokai', 'material'], - overlayShow: false + overlayShow: false, + + // temperature + checked: false } }, async mounted () { @@ -571,6 +574,10 @@ export default { try { const res = await api.getSubmission(id) this.result = res.data.data + if (!this.checked && this.result.result === 0) { + this.checked = true + await api.temperature(this.problem.id) + } if (Object.keys(res.data.data.statistic_info).length !== 0) { this.submitting = false this.submitted = false diff --git a/frontend/src/pages/oj/views/user/Profile.vue b/frontend/src/pages/oj/views/user/Profile.vue index 9053a8202..ee4d9267f 100644 --- a/frontend/src/pages/oj/views/user/Profile.vue +++ b/frontend/src/pages/oj/views/user/Profile.vue @@ -21,7 +21,7 @@