diff --git a/frontend/public/image/png/Stroke.png b/frontend/public/image/png/Stroke.png
new file mode 100644
index 00000000..c7985435
Binary files /dev/null and b/frontend/public/image/png/Stroke.png differ
diff --git a/frontend/public/image/svg/LeftArrow.svg b/frontend/public/image/svg/LeftArrow.svg
new file mode 100644
index 00000000..3c586ad8
--- /dev/null
+++ b/frontend/public/image/svg/LeftArrow.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/public/image/svg/OptionBoxStroke.svg b/frontend/public/image/svg/OptionBoxStroke.svg
new file mode 100644
index 00000000..44a2b0ff
--- /dev/null
+++ b/frontend/public/image/svg/OptionBoxStroke.svg
@@ -0,0 +1,17 @@
+
diff --git a/frontend/public/image/svg/RightArrow.svg b/frontend/public/image/svg/RightArrow.svg
new file mode 100644
index 00000000..4c98ff10
--- /dev/null
+++ b/frontend/public/image/svg/RightArrow.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/public/image/svg/historyMyOptionLine.svg b/frontend/public/image/svg/historyMyOptionLine.svg
new file mode 100644
index 00000000..07d73ade
--- /dev/null
+++ b/frontend/public/image/svg/historyMyOptionLine.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index bb4f2cf6..a4d1e2a8 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -10,6 +10,7 @@ import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from './pages/Home';
import Login from './pages/Login';
import User from './pages/User';
+import History from './pages/History';
function App() {
return (
@@ -20,6 +21,7 @@ function App() {
} />
} />
} />
+ } />
diff --git a/frontend/src/css/History_style.css b/frontend/src/css/History_style.css
new file mode 100644
index 00000000..8b833f6a
--- /dev/null
+++ b/frontend/src/css/History_style.css
@@ -0,0 +1,1005 @@
+/**
+ * Copyright 2023 kyudori, Basaeng, hwan5180, quswjdgma83
+ *
+ * Use of this source code is governed by a MIT license that can be
+ * found in the LICENSE file.
+ */
+
+ .history-send {
+ background-color: #ffffff;
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ width: 100%;
+ position: relative;
+}
+
+.history-send .div {
+ background-color: #ffffff;
+ border: 1px none;
+ height: 1080px;
+ position: relative;
+ width: 1920px;
+}
+
+.history-send .overlap {
+ background-image: url(../../public/image/svg/OptionBoxStroke.svg);
+ background-size: 100% 100%;
+ height: 882px;
+ left: 34px;
+ position: absolute;
+ top: 133px;
+ width: 572px;
+ border-radius: 30px;
+ box-shadow: 0px 4px 4px #00000040, 2px 2px 2px 1px gray;
+ border: 1px solid gray;
+}
+
+.history-send .option-menu {
+ height: 853px;
+ left: 41px;
+ position: relative;
+ top: 13px;
+ width: 482px;
+}
+
+.history-send .button {
+ height: 773px;
+ left: 0;
+ position: absolute;
+ top: 80px;
+ width: 482px;
+}
+
+.history-send .my-pull-request {
+ height: 255px;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 484px;
+ cursor: pointer;
+ transition: background-color 0.3s;
+}
+
+.history-send .my-pull-request:active,
+.history-send .my-pull-request:focus {
+ background-color: #f0f0f0;
+ transform: translateY(4px)
+}
+
+.history-send .overlap-group {
+ background-color: #ffffff;
+ border-radius: 30px;
+ box-shadow: 0px 4px 4px #00000040;
+ height: 255px;
+ position: relative;
+ width: 482px;
+ box-shadow: 0px 4px 4px #00000040, 2px 2px 2px 1px gray;
+ border: 1px solid gray;
+}
+
+.history-send .text-wrapper {
+ color: black;
+ font-family: "Inter-Bold", Helvetica;
+ font-size: 40px;
+ font-weight: 700;
+ left: 84px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 104px;
+ white-space: nowrap;
+}
+
+.history-send .text-wrapper-gray {
+ color: #0057B8;
+ font-family: "Inter-Bold", Helvetica;
+ font-size: 40px;
+ font-weight: 700;
+ left: 84px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 104px;
+ white-space: nowrap;
+}
+
+.history-send .my-repo-pr-button {
+ height: 255px;
+ left: 0;
+ position: absolute;
+ top: 259px;
+ width: 484px;
+ cursor: pointer;
+ transition: background-color 0.3s;
+}
+
+.history-send .my-repo-pr-button:active,
+.history-send .my-repo-pr-button:focus {
+ background-color: #f0f0f0;
+ transform: translateY(4px)
+}
+
+.history-send .my-repo-PR {
+ color: #000000;
+ font-family: "Inter-Bold", Helvetica;
+ font-size: 40px;
+ font-weight: 700;
+ left: 121px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 107px;
+ white-space: nowrap;
+}
+
+.history-send .my-repo-PR-gray {
+ color: #0057B8;
+ font-family: "Inter-Bold", Helvetica;
+ font-size: 40px;
+ font-weight: 700;
+ left: 121px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 107px;
+ white-space: nowrap;
+}
+
+.history-send .my-org-PR-button {
+ height: 255px;
+ left: 0;
+ position: absolute;
+ top: 518px;
+ width: 484px;
+ cursor: pointer;
+ transition: background-color 0.3s
+}
+
+.history-send .my-org-PR-button:active,
+.history-send .my-org-PR-button:focus {
+ background-color: #f0f0f0;
+ transform: translateY(4px)
+}
+
+.history-send .text-wrapper-2 {
+ color: #000000;
+ font-family: "Inter-Bold", Helvetica;
+ font-size: 40px;
+ font-weight: 700;
+ left: 140px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 97px;
+ white-space: nowrap;
+}
+
+.history-send .text-wrapper-2-gray {
+ color: #0057B8;
+ font-family: "Inter-Bold", Helvetica;
+ font-size: 40px;
+ font-weight: 700;
+ left: 140px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 97px;
+ white-space: nowrap;
+}
+
+.history-send .my-option-header {
+ height: 61px;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 484px;
+}
+
+.history-send .my-option-line {
+ left: 0;
+ position: absolute;
+ top: 58px;
+ width: 100%;
+}
+
+.history-send .my-option-line svg {
+ width: 100%;
+ height: 2px;
+ display: block;
+}
+
+
+.history-send .text-wrapper-3 {
+ color: #000000;
+ font-family: "Inter-Bold", Helvetica;
+ font-size: 40px;
+ font-weight: 700;
+ left: 10px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 0;
+ white-space: nowrap;
+}
+
+.history-send .page-move-tool-bar {
+ height: 30px;
+ left: 845px;
+ position: absolute;
+ top: 1027px;
+ width: 286px;
+}
+
+.history-send .page-number {
+ align-items: flex-start;
+ display: inline-flex;
+ gap: 33px;
+ left: 35px;
+ position: absolute;
+ top: 0;
+}
+
+.history-send .text-wrapper-4 {
+ color: #000000;
+ font-family: "Inter-Bold", Helvetica;
+ font-size: 25px;
+ font-weight: 700;
+ letter-spacing: 0;
+ line-height: normal;
+ margin-top: -1px;
+ position: relative;
+ width: 13px;
+ cursor: pointer;
+}
+
+.history-send .text-wrapper-4-blue {
+ color: #0057B8;
+ font-family: "Inter-Bold", Helvetica;
+ font-size: 25px;
+ font-weight: 700;
+ letter-spacing: 0;
+ line-height: normal;
+ margin-top: -1px;
+ position: relative;
+ width: 13px;
+ cursor: pointer;
+}
+
+.history-send .text-wrapper-5 {
+ color: #000000;
+ font-family: "Inter-SemiBold", Helvetica;
+ font-size: 25px;
+ font-weight: 600;
+ letter-spacing: 0;
+ line-height: normal;
+ margin-top: -1px;
+ position: relative;
+ width: 16px;
+ cursor: pointer;
+}
+
+.history-send .text-wrapper-6 {
+ color: #000000;
+ font-family: "Inter-SemiBold", Helvetica;
+ font-size: 25px;
+ font-weight: 600;
+ letter-spacing: 0;
+ line-height: normal;
+ margin-top: -1px;
+ position: relative;
+ width: 17px;
+ cursor: pointer;
+}
+
+.history-send .right-arrow {
+ height: 22px;
+ left: 275px;
+ position: absolute;
+ top: 4px;
+ width: 13px;
+ cursor: pointer;
+}
+
+.history-send .left-arrow {
+ height: 22px;
+ left: -2px;
+ position: absolute;
+ top: 4px;
+ width: 13px;
+ cursor: pointer;
+}
+
+.history-send .overlap-2 {
+ height: 882px;
+ left: 635px;
+ position: absolute;
+ top: 134px;
+ width: 1236px;
+}
+
+.history-send .history-box {
+ height: 882px;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 1236px;
+}
+
+.history-send .history {
+ height: 158px;
+ left: 0;
+ position: absolute;
+ top: 724px;
+ width: 1242px;
+}
+
+.history-send .overlap-3 {
+ background-image: url(../../public/image/png/Stroke.png);
+ background-size: 100% 100%;
+ height: 166px;
+ left: -4px;
+ position: relative;
+ width: 1244px;
+}
+
+.history-send .text-wrapper-7 {
+ color: #000000;
+ font-family: "Inter-Bold", Helvetica;
+ font-size: 25px;
+ font-weight: 700;
+ left: 29px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: relative;
+ top: 15px;
+ display: inline-block;
+}
+
+.text-wrapper-7-container {
+ position: relative;
+}
+
+.history-send .text-wrapper-8 {
+ color: #000000;
+ font-family: "Inter-Medium", Helvetica;
+ font-size: 20px;
+ font-weight: 500;
+ left: 29px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 65px;
+ white-space: nowrap;
+
+
+}
+
+.history-send .text-wrapper-8 ::after {
+ content: counter(name);
+}
+
+.history-send .text-wrapper-9 {
+ color: #000000;
+ font-family: "Inter-Medium", Helvetica;
+ font-size: 20px;
+ font-weight: 500;
+ left: 29px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 105px;
+ white-space: nowrap;
+}
+
+.history-send .prid {
+ height: 26px;
+ left: calc(100% + 20px);
+ position: absolute;
+ top: 4px;
+ width: 77px;
+}
+
+.history-send .div-wrapper {
+ background-color: #d9d9d9;
+ border-radius: 15px;
+ height: 26px;
+ position: absolute;
+ left: 0px;
+ width: 75px;
+}
+
+.history-send .text-wrapper-10 {
+ color: #000000;
+ font-family: "Inter-Medium", Helvetica;
+ font-size: 20px;
+ font-weight: 500;
+ left: 50%;
+ transform: translateX(-50%);
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 2px;
+ white-space: nowrap;
+}
+
+.history-send .status-scan-error {
+ height: 27px;
+ left: calc(100% + 20px);
+ position: absolute;
+ top: 1px;
+ width: 187px;
+}
+
+.history-send .overlap-wrapper {
+ height: 158px;
+ left: 0;
+ position: absolute;
+ top: 543px;
+ width: 1242px;
+}
+
+.history-send .overlap-4 {
+ background-image: url(../../public/image/png/Stroke.png);
+ background-size: 100% 100%;
+ height: 166px;
+ left: -4px;
+ position: relative;
+ width: 1244px;
+}
+
+.history-send .text-wrapper-11 {
+ color: #000000;
+ font-family: "Inter-Bold", Helvetica;
+ font-size: 25px;
+ font-weight: 700;
+ left: 29px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: relative;
+ top: 15px;
+ display: inline-block;
+}
+
+.history-send .p {
+ color: transparent;
+ font-family: "Inter-Medium", Helvetica;
+ font-size: 20px;
+ font-weight: 500;
+ left: 29px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 65px;
+ width: 1150px;
+ white-space: nowrap;
+}
+
+.history-send .span {
+ color: #000000;
+}
+
+.history-send .text-wrapper-12 {
+ color: #0057b8;
+}
+
+.history-send .overlap-group-wrapper {
+ height: 26px;
+ left: calc(100% + 20px);
+ position: absolute;
+ top: 4px;
+ width: 77px;
+}
+
+.history-send .text-wrapper-13 {
+ color: #000000;
+ font-family: "Inter-Medium", Helvetica;
+ font-size: 20px;
+ font-weight: 500;
+ left: 50%;
+ transform: translateX(-50%);
+ white-space: nowrap;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 2px;
+}
+
+.history-send .status-issue {
+ height: 27px;
+ left: calc(100% + 20px);
+ position: absolute;
+ top: 0px;
+ width: 187px;
+}
+
+.history-send .overlap-5 {
+ border-radius: 5px;
+ height: 27px;
+ position: relative;
+ width: 300px;
+}
+
+.history-send .text-wrapper-14 {
+ color: #ff0000;
+ font-family: "Inter-Medium", Helvetica;
+ font-size: 20px;
+ font-weight: 500;
+ left: 18px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 1px;
+ width: 100%;
+}
+
+.history-send .history-2 {
+ height: 158px;
+ left: 0;
+ position: absolute;
+ top: 362px;
+ width: 1242px;
+}
+
+.history-send .overlap-6 {
+ background-image: url(../../public/image/png/Stroke.png);
+ background-size: 100% 100%;
+ height: 166px;
+ left: -4px;
+ position: relative;
+ width: 1244px;
+}
+
+.history-send .text-wrapper-15 {
+ color: #000000;
+ font-family: "Inter-Bold", Helvetica;
+ font-size: 25px;
+ font-weight: 700;
+ left: 29px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: relative;
+ top: 15px;
+ display: inline-block;
+}
+
+.history-send .prid-2 {
+ height: 26px;
+ left: calc(100% + 20px);
+ position: absolute;
+ top: 4px;
+ width: 77px;
+}
+
+.history-send .text-wrapper-16 {
+ color: #000000;
+ font-family: "Inter-Medium", Helvetica;
+ font-size: 20px;
+ font-weight: 500;
+ left: 50%;
+ transform: translateX(-50%);
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 2px;
+ white-space: nowrap;
+}
+
+.history-send .status-scan {
+ height: 27px;
+ left: calc(100% + 20px);
+ position: absolute;
+ top: 0px;
+ width: 187px;
+}
+
+.history-send .issue-detected {
+ color: #0000ff;
+ font-family: "Inter-Medium", Helvetica;
+ font-size: 20px;
+ font-weight: 500;
+ left: 10px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 1px;
+ width: 161px;
+}
+
+.history-send .history-3 {
+ height: 158px;
+ left: 0;
+ position: absolute;
+ top: 181px;
+ width: 1242px;
+}
+
+.history-send .overlap-7 {
+ background-image: url(../../public/image/png/Stroke.png);
+ background-size: 100% 100%;
+ height: 166px;
+ left: -4px;
+ position: relative;
+ width: 1244px;
+}
+
+.history-send .text-wrapper-17 {
+ color: #000000;
+ font-family: "Inter-Bold", Helvetica;
+ font-size: 25px;
+ font-weight: 700;
+ left: 29px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: relative;
+ top: 15px;
+ display: inline-block;
+}
+
+.history-send .prid-3 {
+ height: 26px;
+ left: calc(100% + 20px);
+ position: absolute;
+ top: 4px;
+ width: 77px;
+}
+
+.history-send .text-wrapper-18 {
+ color: #000000;
+ font-family: "Inter-Medium", Helvetica;
+ font-size: 20px;
+ font-weight: 500;
+ left: 50%;
+ transform: translateX(-50%);
+ white-space: nowrap;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 2px;
+}
+
+.history-send .status-scan-2 {
+ height: 27px;
+ left: calc(100% + 20px);
+ position: absolute;
+ top: 0px;
+ width: 187px;
+}
+
+.history-send .overlap-8 {
+ height: 28px;
+ position: relative;
+ width: 185px;
+}
+
+.history-send .history-4 {
+ height: 158px;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 1242px;
+}
+
+.history-send .overlap-9 {
+ background-image: url(../../public/image/png/Stroke.png);
+ background-size: 100% 100%;
+ height: 166px;
+ left: -4px;
+ position: relative;
+ width: 1244px;
+}
+
+.history-send .text-wrapper-19 {
+ color: #000000;
+ font-family: "Inter-Bold", Helvetica;
+ font-size: 25px;
+ font-weight: 700;
+ left: 29px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: relative;
+ top: 16px;
+ display: inline-block;
+}
+
+.history-send .https-github-com-kim {
+ color: transparent;
+ font-family: "Inter-Medium", Helvetica;
+ font-size: 20px;
+ font-weight: 500;
+ left: 28px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 65px;
+ width: 800px;
+}
+
+.history-send .prid-4 {
+ height: 26px;
+ left: calc(100% + 20px);
+ position: absolute;
+ top: 4px;
+ width: 77px;
+}
+
+.history-send .text-wrapper-20 {
+ color: #000000;
+ font-family: "Inter-Medium", Helvetica;
+ font-size: 20px;
+ font-weight: 500;
+ left: 50%;
+ transform: translateX(-50%);
+ white-space: nowrap;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 2px;
+}
+
+.history-send .status-issue-2 {
+ height: 27px;
+ left: calc(100% + 20px);
+ position: absolute;
+ top: 0px;
+ width: 187px;
+}
+
+
+.history-send .text-wrapper-21 {
+ color: #d60000cf;
+ font-family: "Inter-Medium", Helvetica;
+ font-size: 20px;
+ font-weight: 500;
+ left: 44px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 2px;
+ white-space: nowrap;
+ width: 100%
+}
+
+.history-send .menubar-top {
+ height: 101px;
+ left: 39px;
+ position: absolute;
+ top: 8px;
+ width: 1842px;
+}
+
+.history-send .menu-line {
+ background-color: #000000;
+ height: 3px;
+ left: 0;
+ position: absolute;
+ top: 98px;
+ width: 1842px;
+}
+
+.history-send .menu {
+ height: 96px;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 1848px;
+}
+
+.history-send .overlap-11 {
+ height: 43px;
+ left: 1572px;
+ position: absolute;
+ top: 37px;
+ width: 272px;
+}
+
+.history-send .profile-border {
+ background-color: #d9d9d9;
+ height: 3px;
+ left: 104px;
+ position: absolute;
+ top: 20px;
+ transform: rotate(-90deg);
+ width: 40px;
+}
+
+.history-send .text-wrapper-22 {
+ color: #000000;
+ font-family: "Inter-Regular", Helvetica;
+ font-size: 30px;
+ font-weight: 400;
+ left: 1590px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 40px;
+ width: 115px;
+}
+
+.history-send .profile {
+ height: 43px;
+ left: 136px;
+ position: absolute;
+ top: 0;
+ width: 135px;
+}
+
+.history-send .overlap-group-2 {
+ background-color: #d9d9d9;
+ border-radius: 50px;
+ height: 43px;
+ position: relative;
+ width: 133px;
+}
+
+.history-send .image {
+ height: 31px;
+ left: 11px;
+ object-fit: cover;
+ position: absolute;
+ top: 6px;
+ width: 35px;
+}
+
+.history-send .text-wrapper-23 {
+ color: #000000;
+ font-family: "Inter-SemiBold", Helvetica;
+ font-size: 20px;
+ font-weight: 600;
+ left: 56px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 10px;
+ white-space: nowrap;
+ width: 71px;
+}
+
+.history-send .LPVS {
+ height: 96px;
+ left: 0;
+ object-fit: cover;
+ position: absolute;
+ top: 0;
+ width: 229px;
+}
+
+.history-send .complete {
+ color: rgba(0, 0, 255, 1);
+ font-family: Tahoma, Geneva, sans-serif;
+ font-size: 20px;
+ font-weight: 500;
+ letter-spacing: 0;
+ line-height: normal;
+ top: 0px;
+ white-space: nowrap;
+ width: 100%;
+ margin-left: 10px;
+ position: static;
+ z-index: 1;
+}
+
+.history-send .text-wrapper-998 {
+ color: #000000;
+ font-family: "Inter-Medium", Helvetica;
+ font-size: 20px;
+ font-weight: 500;
+ letter-spacing: 0;
+ line-height: normal;
+ top: 0;
+ width: 100%;
+ margin-left: 10px;
+ position: static;
+ right: 0;
+}
+
+.history-send .status-label {
+ background-color: #ff000054;
+ border: 1px solid;
+ border-color: #ff0000;
+ border-radius: 5px;
+ height: 27px;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 185px;
+}
+
+.history-send .status-label-2 {
+ background-color: #0000ff42;
+ border: 1px solid;
+ border-color: #0000ff;
+ border-radius: 5px;
+ height: 27px;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 185px;
+}
+
+.history-send .status-label-3 {
+ background-color: rgba(255, 245, 16, 0.5);
+ border: 1px solid;
+ border-color: #F9EF00;
+ border-radius: 5px;
+ height: 27px;
+ width: 185px;
+ z-index: 1;
+ position: relative;
+}
+
+
+.history-send .Issue-Detected {
+ background-color: #ff000054;
+ border: 2px solid;
+ border-color: #ff0000;
+ border-radius: 5px;
+ height: 27px;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 185px;
+}
+
+.history-send .Scan-completed {
+ background-color: #0000ff42;
+ border: 2px solid;
+ border-color: #0000ff;
+ border-radius: 5px;
+ height: 27px;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 185px;
+}
+
+.history-send .Scan-Error {
+ background-color: rgba(255, 245, 16, 0.5);
+ border: 2px solid;
+ border-color: #3F4311;
+ border-radius: 5px;
+ height: 27px;
+ left: 0;
+ top: 0;
+ width: 185px;
+ z-index: 1;
+}
+
+.history-send .Scan-Error-text {
+ color: #ff0000 !important;
+ font-family: "Inter-Medium", Helvetica;
+ font-size: 20px;
+ font-weight: 500;
+ left: 45px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 3px;
+ width: 100%;
+}
+
+.history-send .Scan-completed-text {
+ color: #0000ff !important;
+ font-family: "Inter-Medium", Helvetica;
+ font-size: 20px;
+ font-weight: 500;
+ left: 21px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 3px;
+ width: 161px;
+}
+
+.history-send .Issue-Detected-text {
+ color: #ff0000 !important;
+ font-family: "Inter-Medium", Helvetica;
+ font-size: 20px;
+ font-weight: 500;
+ left: 26px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 3px;
+ width: 100%;
+}
diff --git a/frontend/src/css/Home_style.css b/frontend/src/css/Home_style.css
index bff757a7..ab11e0a8 100644
--- a/frontend/src/css/Home_style.css
+++ b/frontend/src/css/Home_style.css
@@ -173,6 +173,30 @@
width: 71px;
}
+.home .text-wrapper-7 {
+ color: #000000;
+ font-family: "Inter-Regular", Helvetica;
+ font-size: 30px;
+ font-weight: 400;
+ left: 320px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 3px;
+ white-space: nowrap;
+ width: 104px;
+}
+
+.home .profile-border {
+ background-color: #d9d9d9;
+ height: 3px;
+ left: 104px;
+ position: absolute;
+ top: 20px;
+ transform: rotate(-90deg);
+ width: 40px;
+}
+
.home .LPVS {
height: 96px;
left: 0;
diff --git a/frontend/src/css/User_style.css b/frontend/src/css/User_style.css
index f2d7dbf6..0d7fe5e9 100644
--- a/frontend/src/css/User_style.css
+++ b/frontend/src/css/User_style.css
@@ -220,7 +220,6 @@
white-space: nowrap;
}
-
.user .admit-rect-2 {
border: 1px solid;
border-color: #000000;
@@ -377,8 +376,6 @@
/* click effect eliminate border */
}
-
-
.user .github-ID-box {
height: 50px;
left: 0;
@@ -535,6 +532,30 @@
width: 150px;
}
+ .user .text-wrapper-18 {
+ color: #000000;
+ font-family: "Inter-Regular", Helvetica;
+ font-size: 30px;
+ font-weight: 400;
+ left: 320px;
+ letter-spacing: 0;
+ line-height: normal;
+ position: absolute;
+ top: 3px;
+ white-space: nowrap;
+ width: 104px;
+ }
+
+ .user .profile-border {
+ background-color: #d9d9d9;
+ height: 3px;
+ left: 104px;
+ position: absolute;
+ top: 20px;
+ transform: rotate(-90deg);
+ width: 40px;
+ }
+
.user .LPVS {
height: 96px;
left: 0;
diff --git a/frontend/src/pages/History.jsx b/frontend/src/pages/History.jsx
new file mode 100644
index 00000000..8be2e77e
--- /dev/null
+++ b/frontend/src/pages/History.jsx
@@ -0,0 +1,372 @@
+/**
+ * Copyright 2023 kyudori, Basaeng, hwan5180, quswjdgma83
+ *
+ * Use of this source code is governed by a MIT license that can be
+ * found in the LICENSE file.
+ */
+
+import {React,useEffect, useState} from "react";
+import axios from 'axios';
+import { Link, useParams, useLocation } from "react-router-dom";
+import { useNavigate } from "react-router-dom";
+import "../css/History_style.css";
+
+export const History= () => {
+
+ const { type, name } = useParams();
+ const [ lpvsHistories, setlpvsHistories ] = useState();
+ const navigate = useNavigate();
+
+ const location = useLocation();
+ const queryParams = new URLSearchParams(location.search);
+ const page = queryParams.get('page') || 0;
+
+
+ const [isLoggedIn, setIsLoggedIn] = useState(false);
+ const [username, setUsername] = useState("");
+
+ useEffect(() => {
+ axios.get("/login/check")
+ .then((loginresponse) => {
+ if (loginresponse.data.isLoggedIn) {
+ setIsLoggedIn(loginresponse.data.isLoggedIn);
+ axios.get("/user/info")
+ .then((userInfoResponse) => {
+ setUsername(userInfoResponse.data);
+ })
+ .catch(function(error) {
+ console.log(error.toJSON());
+ navigate("/login");
+ });
+ } else {
+ navigate("/login");
+ }
+ })
+ .catch(function(error) {
+ console.log(error.toJSON());
+ navigate("/login");
+ });
+ }, []);
+
+ useEffect(() => {
+ axios
+ .get(`/history/${type}/${name}?page=${page}`)
+ .then((response) => {
+ console.log(response.data)
+ setlpvsHistories(response.data);
+ })
+ .catch(function(error) {
+ console.log(error.toJSON());
+ const userChoice = window.confirm("Please enter the GitHub ID on the User page.");
+ if (userChoice) {
+ navigate('/user/setting');
+ } else {
+ navigate(`/history/send/${username?.nickname}?page=0`);
+ }
+ });
+ }, [type, name, page]);
+
+ const handlePageChange = (pageNumber) => {
+ navigate(`/history/${type}/${name}?page=${pageNumber}`);
+ };
+
+ const [isHistoriesEmpty, setIsHistoriesEmpty] = useState(false);
+ console.log(lpvsHistories?.lpvsHistories?.length)
+ useEffect(() => {
+ if (lpvsHistories?.lpvsHistories?.length === 0) {
+ setIsHistoriesEmpty(true);
+ } else {
+ setIsHistoriesEmpty(false);
+ }
+ }, [lpvsHistories, page]);
+
+ console.log(lpvsHistories)
+
+ const navigateToOrg = () => {
+ if (!username?.organization || username?.organization.trim() === "") {
+ window.alert("Please enter the Organization information on the User page.");
+ } else {
+ navigate(`/history/org/${username?.organization}?page=0`);
+ }
+ };
+ const navigateToOwn = () => {
+ navigate(`/history/own/${username?.nickname}?page=0`);
+ };
+ const navigateToSend = () => {
+ navigate(`/history/send/${username?.nickname}?page=0`);
+ };
+
+ const [pageCount,setPageCount] = useState(1);
+ const [currentPage, setCurrentPage] = useState(1);
+
+ useEffect(()=> {
+ setPageCount(Math.ceil(lpvsHistories?.count/5))
+ }, [lpvsHistories?.count, currentPage]);
+
+ console.log(pageCount);
+
+ const check_page_plus =()=> {
+ if(currentPage <= pageCount) {
+ console.log(currentPage)
+ return setCurrentPage(currentPage+5);
+ }
+ else {
+ return
+ }
+ }
+ console.log(page);
+ console.log(currentPage);
+ const check_page_minus =(page)=> {
+ if(page <=4) {
+ return setCurrentPage(currentPage)
+ }
+ else {
+ return setCurrentPage(currentPage-5);
+ }
+ }
+
+ const trueOrFalse =(a)=> {
+ if(a <= pageCount) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ const status_check=(a)=> {
+ if(a) {
+ return 'Issue-Detected';
+ }
+ else {
+ return 'Scan-completed';
+ }
+ }
+ console.log(lpvsHistories?.lpvsHistories[0]?.status)
+
+ if (!lpvsHistories) {
+ return
Loading...
;
+ }
+
+ const pageArrow=(page)=> {
+ if(page<=5) {
+ return false;
+ }
+ }
+ console.log(isHistoriesEmpty)
+ return (
+
+
+
+
+
+
+
+
+ {type === "send" ?
+
My Pull Request
+ :
+
My Pull Request
}
+
+
+
+
+ {type === "own" ?
+
My Repo PR
+ :
+
My Repo PR
}
+
+
+
+
+ {type === "org" ?
+
My Org PR
+ :
+
My Org PR
}
+
+
+
+
+
+
+
My Option
+
+
+
+
+
+
{
+ if (page > 4) {
+ check_page_minus();
+ handlePageChange(currentPage - 2);
+ }}} style={{ cursor: "pointer" }} />
+ {trueOrFalse(currentPage) &&
handlePageChange(currentPage-1)}>{currentPage}
}
+ {trueOrFalse(currentPage+1) &&
handlePageChange(currentPage)}>{currentPage+1}
}
+ {trueOrFalse(currentPage+2) &&
handlePageChange(currentPage+1)}>{currentPage+2}
}
+ {trueOrFalse(currentPage+3) &&
handlePageChange(currentPage+2)}>{currentPage+3}
}
+ {trueOrFalse(currentPage+4) &&
handlePageChange(currentPage+3)}>{currentPage+4}
}
+ {trueOrFalse(currentPage+5) ?
{check_page_plus(); handlePageChange(currentPage + 4); }}style={{ cursor: "pointer" }}/>
+ :
+
}
+
+
+
+
+ {lpvsHistories.lpvsHistories[4]?.status !== undefined ? (
+
+
+
+
+
+ {lpvsHistories.lpvsHistories[4]?.repositoryName}
+
+
+
+ {status_check(lpvsHistories.lpvsHistories[4]?.hasIssue)}
+
+
+
+
+
{lpvsHistories.lpvsHistories[4]?.pullNumber}
+
+
+
+
+
+
+
{lpvsHistories.lpvsHistories[4]?.url}
+
{lpvsHistories.lpvsHistories[4]?.scanDate}
+
+
): null}
+
+ {lpvsHistories.lpvsHistories[3]?.status !== undefined ? (
+
+
+
+
+ {lpvsHistories.lpvsHistories[3]?.repositoryName}
+
+
+
{status_check(lpvsHistories.lpvsHistories[3]?.hasIssue)}
+
+
+
+
+
{lpvsHistories.lpvsHistories[3]?.pullNumber}
+
+
+
+
+
+
{lpvsHistories.lpvsHistories[3]?.url}
+
{lpvsHistories.lpvsHistories[3]?.scanDate}
+
+
+ ): null}
+
+ {lpvsHistories.lpvsHistories[2]?.status !== undefined ? (
+
+
+
+
+ {lpvsHistories.lpvsHistories[2]?.repositoryName}
+
+
+
{status_check(lpvsHistories.lpvsHistories[2]?.hasIssue)}
+
+
+
+
+
{lpvsHistories.lpvsHistories[2]?.pullNumber}
+
+
+
+
+
{lpvsHistories.lpvsHistories[2]?.url}
+
{lpvsHistories.lpvsHistories[2]?.scanDate}
+
+
+
+ ): null}
+
+ {lpvsHistories.lpvsHistories[1]?.status !== undefined ? (
+
+
+
+
+ {lpvsHistories.lpvsHistories[1]?.repositoryName}
+
+
+
{status_check(lpvsHistories.lpvsHistories[1]?.hasIssue)}
+
+
+
+
+
{lpvsHistories.lpvsHistories[1]?.pullNumber}
+
+
+
+
+
{lpvsHistories.lpvsHistories[1]?.url}
+
{lpvsHistories.lpvsHistories[1]?.scanDate}
+
+
+
+ ) : null}
+ {lpvsHistories.lpvsHistories[0]?.status !== undefined ? (
+
+
+
+
+ {lpvsHistories.lpvsHistories[0]?.repositoryName}
+
+
+
{status_check(lpvsHistories.lpvsHistories[0]?.hasIssue)}
+
+
+
+
+
{lpvsHistories.lpvsHistories[0]?.pullNumber}
+
+
+
+
+
{lpvsHistories.lpvsHistories[0]?.url}
+
{lpvsHistories.lpvsHistories[0]?.scanDate}
+
+
+
+ ): null}
+
+
+
+
+
+
+
+
+
+
+
+
{username.name}
+
+
+
+
+ History
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default History;
diff --git a/frontend/src/pages/Home.jsx b/frontend/src/pages/Home.jsx
index d68d2982..86e19771 100644
--- a/frontend/src/pages/Home.jsx
+++ b/frontend/src/pages/Home.jsx
@@ -11,120 +11,118 @@ import { Link } from "react-router-dom";
import "../css/Home_style.css";
export const LPVS_SERVER = process.env.REACT_APP_LPVS_SERVER;
+
export const Home = () => {
- const [isLoggedIn, setIsLoggedIn] = useState(false);
- const [username, setUsername] = useState("");
+ const [isLoggedIn, setIsLoggedIn] = useState(false);
+ const [username, setUsername] = useState("");
- useEffect(() => {
- axios.get("/login/check")
- .then((loginresponse) => {
- if (loginresponse.data.isLoggedIn) {
- setIsLoggedIn(loginresponse.data.isLoggedIn);
- axios.get("/user/info").then((userInfoResponse) => {
- setUsername(userInfoResponse.data);
- });
- }
- })
- .catch(function(error) {
- console.log(error.toJSON());
- });
- }, []);
+ useEffect(() => {
+ axios.get("/login/check")
+ .then((loginresponse) => {
+ if (loginresponse.data.isLoggedIn) {
+ setIsLoggedIn(loginresponse.data.isLoggedIn);
+ axios.get("/user/info").then((userInfoResponse) => {
+ setUsername(userInfoResponse.data);
+ });
+ }
+ })
+ .catch(function(error) {
+ console.log(error.toJSON());
+ });
+ }, []);
- function truncateName(name) {
- if (/[\u3131-\u314e\u314f-\u3163\uac00-\ud7a3]/g.test(name)) {
- return name.length > 3 ? `${name.substring(0, 3)}.` : name;
- } else {
- return name.length > 5 ? `${name.substring(0, 5)}.` : name;
+ function truncateName(name) {
+ if (/[\u3131-\u314e\u314f-\u3163\uac00-\ud7a3]/g.test(name)) {
+ return name.length > 3 ? `${name.substring(0, 3)}.` : name;
+ } else {
+ return name.length > 5 ? `${name.substring(0, 5)}.` : name;
+ }
}
- }
- return (
-
-
-
-
-
-
Welcome to the License Pre-Validation Service (LPVS).
-
Usage Procedure
-
- - Sign up and Login to the service.
- - Go to user information page, enter your GitHub ID (required) and Organization Name (optional), then click the "Admit" button.
- - Login to GitHub using the GitHub ID you entered in step 2.
- - To configure the repository for license validation, follow these steps:
-
- - Go to the repository you want to validation.
- - Navigate to Settings -{">"} Webhooks -{">"} Add Webhooks.
- - Enter 'http://{"<"}IP where LPVS is running:7896/webhooks{">"}' in the Payload URL field.
- - Select 'application/json' for Content Type.
- - Enter 'LPVS' in the Secret field.
- - Under "Which events would you like to trigger this webhook?", select 'Let me select individual events.' and check only the 'Pull Request' option.
- - Click the green 'Add webhook' button.
-
- - After completing the webhook setup for the repository, create a Pull Request on that repository to see the results of license validation.
-
-
Important Notes
-
- - If you enter a GitHub ID that is already used by someone else in your user information, it will not be reflected.
- - This service is only available for Public Repository.
- - Webhook settings are mandatory for using this service.
-
-
-
-
-
-
-
-
-
- License
- Pre
- Validation
- Service
-
-
About
-
-
-
-
-
-
-
-
-
-
- {isLoggedIn ? (
-
-
- {username?.name ? (
- {truncateName(username.name)}
- ) : (
- Loading...
- )}
-
-
- ) : (
-
- Login
-
- )}
-
+ return (
+
+
+
+
+
+
Welcome to the License Pre-Validation Service (LPVS).
+
Usage Procedure
+
+ - Sign up and Login to the service.
+ - Go to user information page, enter your GitHub ID (required) and Organization Name (optional), then click the "Admit" button.
+ - Login to GitHub using the GitHub ID you entered in step 2.
+ - To configure the repository for license validation, follow these steps:
+
+ - Go to the repository you want to validation.
+ - Navigate to Settings -{">"} Webhooks -{">"} Add Webhooks.
+ - Enter 'http://{"<"}IP where LPVS is running:7896/webhooks{">"}' in the Payload URL field.
+ - Select 'application/json' for Content Type.
+ - Enter 'LPVS' in the Secret field.
+ - Under "Which events would you like to trigger this webhook?", select 'Let me select individual events.' and check only the 'Pull Request' option.
+ - Click the green 'Add webhook' button.
+
+ - After completing the webhook setup for the repository, create a Pull Request on that repository to see the results of license validation.
+
+
Important Notes
+
+ - If you enter a GitHub ID that is already used by someone else in your user information, it will not be reflected.
+ - This service is only available for Public Repository.
+ - Webhook settings are mandatory for using this service.
+
+
+
+
+
+
+
+
+
+ License
+ Pre
+ Validation
+ Service
+
+
About
+
+
+
+
+
+ {isLoggedIn ?
: null}
+
+
+
+
+ {isLoggedIn ? (
+
+
+ {username?.name ? {truncateName(username.name)}
: Loading...
}
+
+
+ ) : (
+
+ Login
+
+ )}
+
+
+
+
+
+ {isLoggedIn ? (
+
+ History
+
+ ) : null}
+
+
+
+
+
-
-
-
-
-
-
-
- );
+ );
};
export default Home;
diff --git a/frontend/src/pages/User.jsx b/frontend/src/pages/User.jsx
index c85b7f80..414e8c1c 100644
--- a/frontend/src/pages/User.jsx
+++ b/frontend/src/pages/User.jsx
@@ -109,6 +109,17 @@ export const User = () => {
}));
};
+ const handleHistoryLinkClick = (event) => {
+ event.preventDefault();
+
+ if (!userInfo?.nickname) {
+ alert('To use service, You must enter a GitHub ID.');
+ navigate('/user/setting');
+ } else {
+ navigate(`/history/send/${userInfo.nickname}`);
+ }
+ };
+
const handleLogoClick = (event) => {
event.preventDefault();
@@ -255,6 +266,7 @@ export const User = () => {
+
@@ -275,6 +287,14 @@ export const User = () => {
+
+
+ History
+
+
customAttribute = customAttribute(attributes, userNameAttributeName,
memberProfile, registrationId);
diff --git a/src/main/java/com/lpvs/controller/LPVSWebController.java b/src/main/java/com/lpvs/controller/LPVSWebController.java
index 2e17b7c8..4de264ed 100644
--- a/src/main/java/com/lpvs/controller/LPVSWebController.java
+++ b/src/main/java/com/lpvs/controller/LPVSWebController.java
@@ -7,24 +7,39 @@
package com.lpvs.controller;
-import com.lpvs.entity.LPVSLoginMember;
-import com.lpvs.entity.LPVSMember;
+import com.lpvs.entity.*;
+import com.lpvs.entity.history.HistoryEntity;
+import com.lpvs.entity.history.HistoryPageEntity;
+import com.lpvs.entity.history.LPVSHistory;
+import com.lpvs.entity.result.LPVSResult;
+import com.lpvs.entity.result.LPVSResultFile;
+import com.lpvs.entity.result.LPVSResultInfo;
import com.lpvs.repository.LPVSDetectedLicenseRepository;
import com.lpvs.repository.LPVSLicenseRepository;
import com.lpvs.repository.LPVSMemberRepository;
import com.lpvs.repository.LPVSPullRequestRepository;
import com.lpvs.service.LPVSLoginCheckService;
-import org.springframework.beans.factory.annotation.Value;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
+import java.sql.Timestamp;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
import java.util.Map;
@Controller
+@Slf4j
public class LPVSWebController implements ErrorController {
private LPVSMemberRepository memberRepository;
private LPVSDetectedLicenseRepository detectedLicenseRepository;
@@ -54,7 +69,6 @@ public LPVSMember personalInfoSettings(Authentication authentication) {
public LPVSLoginMember loginMember(Authentication authentication) {
Map
oauthLoginMemberMap = lpvsLoginCheckService.getOauthLoginMemberMap(authentication);
boolean isLoggedIn = oauthLoginMemberMap == null || oauthLoginMemberMap.isEmpty();
-
if (!isLoggedIn) {
LPVSMember findMember = lpvsLoginCheckService.getMemberFromMemberMap(authentication);
return new LPVSLoginMember(!isLoggedIn, findMember);
@@ -77,6 +91,37 @@ public ResponseEntity postSettingTest(@RequestBody Map prPage = historyPageEntity.getPrPage();
+ Long count = historyPageEntity.getCount();
+
+ List lpvsHistories = new ArrayList<>();
+ List lpvsPullRequests = prPage.getContent();
+
+ for (LPVSPullRequest pr : lpvsPullRequests) {
+ String[] pullNumberTemp = pr.getPullRequestUrl().split("/");
+ LocalDateTime localDateTime = new Timestamp(pr.getDate().getTime()).toLocalDateTime();
+ String formattingDateTime = lpvsLoginCheckService.dateTimeFormatting(localDateTime);
+
+ Boolean hasIssue = detectedLicenseRepository.existsIssue(pr);
+
+ lpvsHistories.add(new LPVSHistory(formattingDateTime, pr.getRepositoryName(), pr.getId(),
+ pr.getPullRequestUrl(), pr.getStatus(), pr.getSender(),
+ pullNumberTemp[pullNumberTemp.length-2] + "/" +
+ pullNumberTemp[pullNumberTemp.length-1], hasIssue));
+ }
+
+ HistoryEntity historyEntity = new HistoryEntity(lpvsHistories, count);
+ return historyEntity;
+ }
+
@GetMapping("error")
public String redirect(){
return "index.html";
diff --git a/src/main/java/com/lpvs/entity/LPVSMember.java b/src/main/java/com/lpvs/entity/LPVSMember.java
index e4690ee6..68eab363 100644
--- a/src/main/java/com/lpvs/entity/LPVSMember.java
+++ b/src/main/java/com/lpvs/entity/LPVSMember.java
@@ -63,9 +63,4 @@ public void setOrganization(String organization) {
this.organization = organization;
}
- public void setJoin(String name, String email, String provider) {
- this.name = name;
- this.email = email;
- this.provider = provider;
- }
}
diff --git a/src/main/java/com/lpvs/entity/LPVSPullRequest.java b/src/main/java/com/lpvs/entity/LPVSPullRequest.java
index 39a98a3f..9179416c 100644
--- a/src/main/java/com/lpvs/entity/LPVSPullRequest.java
+++ b/src/main/java/com/lpvs/entity/LPVSPullRequest.java
@@ -45,6 +45,15 @@ public class LPVSPullRequest implements Serializable {
@Column(name = "status")
private String status;
+ @Column(name = "pull_request_head")
+ private String pullRequestHead;
+
+ @Column(name = "pull_request_base")
+ private String pullRequestBase;
+
+ @Column(name = "sender")
+ private String sender;
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/src/main/java/com/lpvs/entity/LPVSQueue.java b/src/main/java/com/lpvs/entity/LPVSQueue.java
index abea0c4f..688e7b7c 100644
--- a/src/main/java/com/lpvs/entity/LPVSQueue.java
+++ b/src/main/java/com/lpvs/entity/LPVSQueue.java
@@ -57,6 +57,14 @@ public class LPVSQueue implements Serializable {
@Column(name = "commit_sha", columnDefinition = "LONGTEXT")
private String headCommitSHA;
+ @Column(name = "pull_request_head")
+ private String pullRequestHead;
+
+ @Column(name = "pull_request_base")
+ private String pullRequestBase;
+
+ @Column(name = "sender")
+ private String sender;
@Transient
private String repositoryLicense;
diff --git a/src/main/java/com/lpvs/entity/history/HistoryEntity.java b/src/main/java/com/lpvs/entity/history/HistoryEntity.java
new file mode 100644
index 00000000..312c6021
--- /dev/null
+++ b/src/main/java/com/lpvs/entity/history/HistoryEntity.java
@@ -0,0 +1,20 @@
+/**
+ * Copyright 2023 Basaeng, kyudori, hwan5180, quswjdgma83
+ *
+ * Use of this source code is governed by a MIT license that can be
+ * found in the LICENSE file.
+ */
+
+package com.lpvs.entity.history;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.List;
+
+@Getter
+@AllArgsConstructor
+public class HistoryEntity {
+ private List lpvsHistories;
+ private Long count;
+}
diff --git a/src/main/java/com/lpvs/entity/history/HistoryPageEntity.java b/src/main/java/com/lpvs/entity/history/HistoryPageEntity.java
new file mode 100644
index 00000000..41c0335f
--- /dev/null
+++ b/src/main/java/com/lpvs/entity/history/HistoryPageEntity.java
@@ -0,0 +1,19 @@
+/**
+ * Copyright 2023 Basaeng, kyudori, hwan5180, quswjdgma83
+ *
+ * Use of this source code is governed by a MIT license that can be
+ * found in the LICENSE file.
+ */
+
+package com.lpvs.entity.history;
+
+import com.lpvs.entity.LPVSPullRequest;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.springframework.data.domain.Page;
+
+@Getter @AllArgsConstructor
+public class HistoryPageEntity {
+ private Page prPage;
+ private Long count;
+}
diff --git a/src/main/java/com/lpvs/entity/history/LPVSHistory.java b/src/main/java/com/lpvs/entity/history/LPVSHistory.java
new file mode 100644
index 00000000..2014b3fc
--- /dev/null
+++ b/src/main/java/com/lpvs/entity/history/LPVSHistory.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright 2023 Basaeng, kyudori, hwan5180, quswjdgma83
+ *
+ * Use of this source code is governed by a MIT license that can be
+ * found in the LICENSE file.
+ */
+
+package com.lpvs.entity.history;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter @Setter @AllArgsConstructor
+public class LPVSHistory {
+ private String scanDate;
+ private String repositoryName;
+ private Long pullRequestId;
+ private String url;
+ private String status;
+ private String sender;
+ private String pullNumber; // pull/number
+ private Boolean hasIssue;
+}
diff --git a/src/main/java/com/lpvs/entity/result/LPVSResult.java b/src/main/java/com/lpvs/entity/result/LPVSResult.java
new file mode 100644
index 00000000..9656643b
--- /dev/null
+++ b/src/main/java/com/lpvs/entity/result/LPVSResult.java
@@ -0,0 +1,23 @@
+package com.lpvs.entity.result;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+import java.util.Map;
+
+@Setter
+@Getter
+@AllArgsConstructor
+public class LPVSResult {
+ private List lpvsResultFileList;
+ private LPVSResultInfo lpvsResultInfo;
+ private Long count;
+
+ private Map licenseCountMap;
+
+ private String pullNumber;
+
+ private Boolean hasIssue;
+}
diff --git a/src/main/java/com/lpvs/entity/result/LPVSResultFile.java b/src/main/java/com/lpvs/entity/result/LPVSResultFile.java
new file mode 100644
index 00000000..f93f4a85
--- /dev/null
+++ b/src/main/java/com/lpvs/entity/result/LPVSResultFile.java
@@ -0,0 +1,17 @@
+package com.lpvs.entity.result;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter @AllArgsConstructor
+public class LPVSResultFile {
+
+ private Long id;
+ private String path;
+ private String componentFileUrl;
+ private String matchLine;
+ private String matchValue;
+
+ private String status; //license.licenseUsage
+ private String licenseSpdx; //license
+}
diff --git a/src/main/java/com/lpvs/entity/result/LPVSResultInfo.java b/src/main/java/com/lpvs/entity/result/LPVSResultInfo.java
new file mode 100644
index 00000000..1380957c
--- /dev/null
+++ b/src/main/java/com/lpvs/entity/result/LPVSResultInfo.java
@@ -0,0 +1,18 @@
+package com.lpvs.entity.result;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+import java.util.List;
+
+@Getter @Setter @AllArgsConstructor
+public class LPVSResultInfo {
+
+ private Long id;
+ private Date scanDate;
+ private String repositoryName;
+ private String status;
+ private List detectedLicenses;
+}
diff --git a/src/main/java/com/lpvs/exception/PageControllerAdvice.java b/src/main/java/com/lpvs/exception/PageControllerAdvice.java
index a97a365e..2010a19a 100644
--- a/src/main/java/com/lpvs/exception/PageControllerAdvice.java
+++ b/src/main/java/com/lpvs/exception/PageControllerAdvice.java
@@ -26,6 +26,13 @@ public ResponseEntity loginFailedHandle(LoginFailedException e) {
return new ResponseEntity<>(errorResponse, HttpStatus.UNAUTHORIZED);
}
+ @ExceptionHandler(WrongAccessException.class)
+ public ResponseEntity wrongAccessHandle(WrongAccessException e) {
+ log.error("wrongAccess");
+ errorResponse = new ErrorResponse(e.getMessage(), HttpStatus.FORBIDDEN.name(), HttpStatus.FORBIDDEN.value());
+ return new ResponseEntity<>(errorResponse, HttpStatus.FORBIDDEN);
+ }
+
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity handleSQLException(IllegalArgumentException e) {
log.error("duplicated key exception" + e.getMessage());
diff --git a/src/main/java/com/lpvs/exception/WrongAccessException.java b/src/main/java/com/lpvs/exception/WrongAccessException.java
new file mode 100644
index 00000000..3044343f
--- /dev/null
+++ b/src/main/java/com/lpvs/exception/WrongAccessException.java
@@ -0,0 +1,15 @@
+/**
+ * Copyright 2023 Basaeng, kyudori, hwan5180, quswjdgma83
+ *
+ * Use of this source code is governed by a MIT license that can be
+ * found in the LICENSE file.
+ */
+
+package com.lpvs.exception;
+
+public class WrongAccessException extends RuntimeException {
+
+ public WrongAccessException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/com/lpvs/repository/LPVSDetectedLicenseRepository.java b/src/main/java/com/lpvs/repository/LPVSDetectedLicenseRepository.java
index 3a9cdea6..da713c58 100644
--- a/src/main/java/com/lpvs/repository/LPVSDetectedLicenseRepository.java
+++ b/src/main/java/com/lpvs/repository/LPVSDetectedLicenseRepository.java
@@ -8,7 +8,25 @@
package com.lpvs.repository;
import com.lpvs.entity.LPVSDetectedLicense;
+import com.lpvs.entity.LPVSLicense;
+import com.lpvs.entity.LPVSPullRequest;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+import java.util.List;
public interface LPVSDetectedLicenseRepository extends JpaRepository {
+ @Query(value = "select count(dl)>0 from LPVSDetectedLicense dl where dl.issue = True and dl.pullRequest = :pr")
+ Boolean existsIssue(@Param("pr") LPVSPullRequest pr);
+
+ List findByPullRequest(LPVSPullRequest lpvsPullRequest);
+ Page findByPullRequest(LPVSPullRequest lpvsPullRequest, Pageable pageable);
+
+
+ @Query(value = "select count(*) from LPVSDetectedLicense dl where dl.pullRequest = :pr and dl.license is not null")
+ Long CountByDetectedLicenseWherePullRequestId(@Param("pr") LPVSPullRequest pr);
+
}
diff --git a/src/main/java/com/lpvs/repository/LPVSLicenseRepository.java b/src/main/java/com/lpvs/repository/LPVSLicenseRepository.java
index b99580e6..6f0680aa 100644
--- a/src/main/java/com/lpvs/repository/LPVSLicenseRepository.java
+++ b/src/main/java/com/lpvs/repository/LPVSLicenseRepository.java
@@ -26,4 +26,5 @@ public interface LPVSLicenseRepository extends CrudRepository
@Query(value = "SELECT * FROM licenses WHERE licenses.license_alternative_names LIKE %:licenseName% ORDER BY id DESC LIMIT 1", nativeQuery = true)
LPVSLicense searchByAlternativeLicenseNames(@Param("licenseName") String licenseName);
+
}
diff --git a/src/main/java/com/lpvs/repository/LPVSPullRequestRepository.java b/src/main/java/com/lpvs/repository/LPVSPullRequestRepository.java
index 56388514..d0b0c375 100644
--- a/src/main/java/com/lpvs/repository/LPVSPullRequestRepository.java
+++ b/src/main/java/com/lpvs/repository/LPVSPullRequestRepository.java
@@ -8,12 +8,41 @@
package com.lpvs.repository;
import com.lpvs.entity.LPVSPullRequest;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
import java.util.Date;
public interface LPVSPullRequestRepository extends JpaRepository {
@Query(value = "SELECT now();", nativeQuery = true)
Date getNow();
+
+ @Query(value = "select pr from LPVSPullRequest pr where pr.repositoryName like :name%")
+ Page findPullRequestByNameLike(@Param("name") String name, Pageable pageable);
+
+ @Query(value = "select count(*) from LPVSPullRequest pr where pr.repositoryName like :name%")
+ Long CountByPullRequestWhereNameLike(@Param("name") String name);
+
+ @Query(value = "select pr from LPVSPullRequest pr where pr.sender = :name")
+ Page findBySender(@Param("name") String name, Pageable pageable);
+
+ @Query(value = "select count(*) from LPVSPullRequest pr where pr.sender = :name")
+ Long CountBySender(@Param("name") String name);
+
+ @Query(value = "select pr from LPVSPullRequest pr where pr.pullRequestBase = :name")
+ Page findByPullRequestBase(@Param("name") String name, Pageable pageable);
+
+ @Query(value = "select count(*) from LPVSPullRequest pr where pr.pullRequestBase = :name")
+ Long CountByPullRequestBase(@Param("name") String name);
+
+ @Query(value = "select pr from LPVSPullRequest pr where pr.sender = :name or pr.pullRequestHead = :name")
+ Page findBySenderOrPullRequestHead(@Param("name") String name, Pageable pageable);
+
+ @Query(value = "select count(*) from LPVSPullRequest pr where pr.sender = :name or pr.pullRequestHead = :name")
+ Long CountBySenderOrPullRequestHead(@Param("name") String name);
+
+
}
diff --git a/src/main/java/com/lpvs/service/LPVSLoginCheckService.java b/src/main/java/com/lpvs/service/LPVSLoginCheckService.java
index bb6adab5..24a299db 100644
--- a/src/main/java/com/lpvs/service/LPVSLoginCheckService.java
+++ b/src/main/java/com/lpvs/service/LPVSLoginCheckService.java
@@ -8,16 +8,21 @@
package com.lpvs.service;
import com.lpvs.entity.LPVSMember;
+import com.lpvs.entity.LPVSPullRequest;
+import com.lpvs.entity.history.HistoryPageEntity;
import com.lpvs.exception.LoginFailedException;
+import com.lpvs.exception.WrongAccessException;
import com.lpvs.repository.LPVSMemberRepository;
import com.lpvs.repository.LPVSPullRequestRepository;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
import java.util.Map;
-import java.util.Optional;
@Service
public class LPVSLoginCheckService {
@@ -46,22 +51,41 @@ public void loginVerification(Authentication authentication) {
}
}
- @Transactional
public LPVSMember getMemberFromMemberMap(Authentication authentication) {
Map memberMap = getOauthLoginMemberMap(authentication);
- String name = (String) memberMap.get("name");
String email = (String) memberMap.get("email");
String provider = (String) memberMap.get("provider");
- Optional findMemberOptional = memberRepository.findByEmailAndProvider(email, provider);
+ LPVSMember findMember = memberRepository.findByEmailAndProvider(email, provider).get();
- if (findMemberOptional.isPresent()) {
- return findMemberOptional.get();
+ return findMember;
+ }
+
+ public HistoryPageEntity pathCheck(String type, String name,
+ Pageable pageable, Authentication authentication) {
+
+ loginVerification(authentication);
+ LPVSMember findMember = getMemberFromMemberMap(authentication);
+ String findNickName = findMember.getNickname();
+ String findOrganization = findMember.getOrganization();
+ Page prPage;
+ Long count;
+
+ if ((type.equals("own") && findNickName.equals(name)) ||
+ (type.equals("org") && findOrganization.equals(name))) {
+ prPage = lpvsPullRequestRepository.findByPullRequestBase(name, pageable);
+ count = lpvsPullRequestRepository.CountByPullRequestBase(name);
+ } else if (type.equals("send") && findNickName.equals(name)) {
+ prPage = lpvsPullRequestRepository.findBySenderOrPullRequestHead(name, pageable);
+ count = lpvsPullRequestRepository.CountBySenderOrPullRequestHead(name);
} else {
- LPVSMember newMember = new LPVSMember();
- newMember.setJoin(name, email, provider);
- memberRepository.save(newMember);
- return newMember;
+ throw new WrongAccessException("WrongAccessException");
}
+
+ return new HistoryPageEntity(prPage, count);
+ }
+
+ public String dateTimeFormatting(LocalDateTime localDateTime) {
+ return localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
}
diff --git a/src/main/java/com/lpvs/service/LPVSQueueService.java b/src/main/java/com/lpvs/service/LPVSQueueService.java
index b1df41bd..c9c27661 100644
--- a/src/main/java/com/lpvs/service/LPVSQueueService.java
+++ b/src/main/java/com/lpvs/service/LPVSQueueService.java
@@ -97,6 +97,9 @@ public void checkForQueue() throws InterruptedException {
pullRequest.setRepositoryName(LPVSWebhookUtil.getRepositoryOrganization(webhook) + "/" + LPVSWebhookUtil.getRepositoryName(webhook));
pullRequest.setDate(webhook.getDate());
pullRequest.setStatus(LPVSPullRequestStatus.NO_ACCESS.toString());
+ pullRequest.setPullRequestHead(webhook.getPullRequestHead());
+ pullRequest.setPullRequestBase(webhook.getPullRequestBase());
+ pullRequest.setSender(webhook.getSender());
pullRequest = lpvsPullRequestRepository.saveAndFlush(pullRequest);
if (webhook.getUserId().equals("GitHub hook")) {
@@ -136,6 +139,9 @@ public void processWebHook(LPVSQueue webhookConfig) throws IOException {
pullRequest.setRepositoryName(LPVSWebhookUtil.getRepositoryOrganization(webhookConfig) + "/" + LPVSWebhookUtil.getRepositoryName(webhookConfig));
pullRequest.setDate(webhookConfig.getDate());
pullRequest.setStatus(LPVSPullRequestStatus.SCANNING.toString());
+ pullRequest.setPullRequestHead(webhookConfig.getPullRequestHead());
+ pullRequest.setPullRequestBase(webhookConfig.getPullRequestBase());
+ pullRequest.setSender(webhookConfig.getSender());
pullRequest = lpvsPullRequestRepository.saveAndFlush(pullRequest);
log.debug("ID: " + pullRequest.getId() + " " + pullRequest.toString());
diff --git a/src/main/java/com/lpvs/util/LPVSWebhookUtil.java b/src/main/java/com/lpvs/util/LPVSWebhookUtil.java
index d237b471..35451bc0 100644
--- a/src/main/java/com/lpvs/util/LPVSWebhookUtil.java
+++ b/src/main/java/com/lpvs/util/LPVSWebhookUtil.java
@@ -38,6 +38,10 @@ public static LPVSQueue getGitHubWebhookConfig(String payload) {
webhookConfig.setHeadCommitSHA(json.getAsJsonObject("pull_request")
.getAsJsonObject("head")
.get("sha").getAsString());
+
+ webhookConfig.setPullRequestBase(json.getAsJsonObject("pull_request").getAsJsonObject("base").getAsJsonObject("repo").getAsJsonObject("owner").get("login").getAsString());
+ webhookConfig.setPullRequestHead(json.getAsJsonObject("pull_request").getAsJsonObject("head").getAsJsonObject("repo").getAsJsonObject("owner").get("login").getAsString());
+ webhookConfig.setSender(json.getAsJsonObject("sender").get("login").getAsString());
webhookConfig.setAttempts(0);
return webhookConfig;
}
diff --git a/src/main/resources/database_dump.sql b/src/main/resources/database_dump.sql
index f03ed74c..ad61453e 100644
--- a/src/main/resources/database_dump.sql
+++ b/src/main/resources/database_dump.sql
@@ -90,6 +90,9 @@ CREATE TABLE `pull_requests` (
`url` longtext NOT NULL,
`diff_url` longtext,
`status` varchar(255) DEFAULT NULL,
+ `pull_request_head` varchar(255) NOT NULL,
+ `pull_request_base` varchar(255) NOT NULL,
+ `sender` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
diff --git a/src/test/java/com/lpvs/controller/GitHubWebhooksControllerTest.java b/src/test/java/com/lpvs/controller/GitHubWebhooksControllerTest.java
index 254a9e81..039981ab 100644
--- a/src/test/java/com/lpvs/controller/GitHubWebhooksControllerTest.java
+++ b/src/test/java/com/lpvs/controller/GitHubWebhooksControllerTest.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2022, Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2023, Samsung Electronics Co., Ltd. All rights reserved.
*
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
@@ -76,8 +76,18 @@ public void okTest() {
"}, " +
"\"pull_request\": {" +
"\"html_url\": \"https://github.com/Samsung/LPVS/pull/18\", " +
+ "\"base\": {" +
+ "\"repo\": {" +
+ "\"owner\": {" +
+ "\"login\": \"Samsung\"" +
+ "}" +
+ "}" +
+ "}," +
"\"head\": {" +
"\"repo\": {" +
+ "\"owner\": {" +
+ "\"login\": \"o-kopysov\"" +
+ "}," +
"\"fork\": true, " +
"\"html_url\": \"https://github.com/o-kopysov/LPVS/tree/utests\"" +
"}, " +
@@ -85,6 +95,9 @@ public void okTest() {
"\"ref\": \"o-kopysov:utests\"" +
"}, " +
"\"url\": \"https://api.github.com/repos/Samsung/LPVS/pulls/18\"" +
+ "}," +
+ "\"sender\": {" +
+ "\"login\": \"o-kopysov\"" +
"}" +
"}";
diff --git a/src/test/java/com/lpvs/entity/LPVSPullRequestTest.java b/src/test/java/com/lpvs/entity/LPVSPullRequestTest.java
index 0ee2feb0..a9fdf7e1 100644
--- a/src/test/java/com/lpvs/entity/LPVSPullRequestTest.java
+++ b/src/test/java/com/lpvs/entity/LPVSPullRequestTest.java
@@ -25,6 +25,10 @@ public class LPVSPullRequestTest {
final String pullRequestUrl = "pulRequestUrl";
final String pullRequestFilesUrl = "pullRequestFileUrl";
final String status = "status";
+ final String pullRequestBase = "user";
+ final String pullRequestHead = "user";
+ final String sender = "user";
+
@BeforeEach
void setUp() {
@@ -34,7 +38,10 @@ void setUp() {
repositoryName,
pullRequestUrl,
pullRequestFilesUrl,
- status);
+ status,
+ pullRequestBase,
+ pullRequestHead,
+ sender);
}
@Test
diff --git a/src/test/java/com/lpvs/util/WebHookUtilTest.java b/src/test/java/com/lpvs/util/WebHookUtilTest.java
index 1cdfa3b0..6ce62140 100644
--- a/src/test/java/com/lpvs/util/WebHookUtilTest.java
+++ b/src/test/java/com/lpvs/util/WebHookUtilTest.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2022, Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2023, Samsung Electronics Co., Ltd. All rights reserved.
*
* Use of this source code is governed by a MIT license that can be
* found in the LICENSE file.
@@ -34,8 +34,18 @@ void setUp() {
"}, " +
"\"pull_request\": {" +
"\"html_url\": \"https://github.com/Samsung/LPVS/pull/18\", " +
+ "\"base\": {" +
+ "\"repo\": {" +
+ "\"owner\": {" +
+ "\"login\": \"Samsung\"" +
+ "}" +
+ "}" +
+ "}, " +
"\"head\": {" +
"\"repo\": {" +
+ "\"owner\": {" +
+ "\"login\": \"o-kopysov\"" +
+ "}," +
"\"fork\": true, " +
"\"html_url\": \"https://github.com/o-kopysov/LPVS/tree/utests\"" +
"}, " +
@@ -43,6 +53,9 @@ void setUp() {
"\"ref\": \"o-kopysov:utests\"" +
"}, " +
"\"url\": \"https://api.github.com/repos/Samsung/LPVS/pulls/18\"" +
+ "}," +
+ "\"sender\": {" +
+ "\"login\": \"o-kopysov\"" +
"}" +
"}";
@@ -53,6 +66,9 @@ void setUp() {
expected.setPullRequestAPIUrl("https://api.github.com/repos/Samsung/LPVS/pulls/18");
expected.setRepositoryUrl("https://github.com/Samsung/LPVS");
expected.setUserId("GitHub hook");
+ expected.setPullRequestBase("Samsung");
+ expected.setPullRequestHead("o-kopysov");
+ expected.setSender("o-kopysov");
expected.setHeadCommitSHA("edde69ecb8e8a88dde09fa9789e2c9cab7cf7cf9");
expected.setAttempts(0);
}
@@ -82,8 +98,18 @@ void setUp() {
"}, " +
"\"pull_request\": {" +
"\"html_url\": \"https://github.com/Samsung/LPVS/pull/18\", " +
+ "\"base\": {" +
+ "\"repo\": {" +
+ "\"owner\": {" +
+ "\"login\": \"Samsung\"" +
+ "}" +
+ "}" +
+ "}, " +
"\"head\": {" +
"\"repo\": {" +
+ "\"owner\": {" +
+ "\"login\": \"o-kopysov\"" +
+ "}," +
"\"fork\": false, " +
"\"html_url\": \"https://github.com/o-kopysov/LPVS/tree/utests\"" +
"}, " +
@@ -91,6 +117,9 @@ void setUp() {
"\"ref\": \"o-kopysov:utests\"" +
"}, " +
"\"url\": \"https://api.github.com/repos/Samsung/LPVS/pulls/18\"" +
+ "}," +
+ "\"sender\": {" +
+ "\"login\": \"o-kopysov\"" +
"}" +
"}";
@@ -101,6 +130,9 @@ void setUp() {
expected.setPullRequestAPIUrl("https://api.github.com/repos/Samsung/LPVS/pulls/18");
expected.setRepositoryUrl("https://github.com/Samsung/LPVS");
expected.setUserId("GitHub hook");
+ expected.setPullRequestBase("Samsung");
+ expected.setPullRequestHead("o-kopysov");
+ expected.setSender("o-kopysov");
expected.setHeadCommitSHA("edde69ecb8e8a88dde09fa9789e2c9cab7cf7cf9");
expected.setAttempts(0);
}