diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..35410ca
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/gin-gorm-oj.iml b/.idea/gin-gorm-oj.iml
new file mode 100644
index 0000000..5e764c4
--- /dev/null
+++ b/.idea/gin-gorm-oj.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/go.imports.xml b/.idea/go.imports.xml
new file mode 100644
index 0000000..7313580
--- /dev/null
+++ b/.idea/go.imports.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..7d71151
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/00c0541c-ee12-47a7-9d0f-cf0c5a39e09c/main.go b/code/00c0541c-ee12-47a7-9d0f-cf0c5a39e09c/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/00c0541c-ee12-47a7-9d0f-cf0c5a39e09c/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/09bb8c34-a627-4231-86f1-73ebbd9b1582/main.go b/code/09bb8c34-a627-4231-86f1-73ebbd9b1582/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/09bb8c34-a627-4231-86f1-73ebbd9b1582/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/0ddbdc45-1cc1-4b1b-ab0e-d43b6ec2bc24/main.go b/code/0ddbdc45-1cc1-4b1b-ab0e-d43b6ec2bc24/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/0ddbdc45-1cc1-4b1b-ab0e-d43b6ec2bc24/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/10e34d06-b2e3-43f9-b993-605ea662a777/main.go b/code/10e34d06-b2e3-43f9-b993-605ea662a777/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/10e34d06-b2e3-43f9-b993-605ea662a777/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/1428deb5-fc2e-4a1c-b16f-32d86109b9cf/main.go b/code/1428deb5-fc2e-4a1c-b16f-32d86109b9cf/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/1428deb5-fc2e-4a1c-b16f-32d86109b9cf/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/1cb7600e-ab76-4369-99a6-4ca30753ccb4/main.go b/code/1cb7600e-ab76-4369-99a6-4ca30753ccb4/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/1cb7600e-ab76-4369-99a6-4ca30753ccb4/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/20919172-2e92-47a9-b4b1-bbce938d0e91/main.go b/code/20919172-2e92-47a9-b4b1-bbce938d0e91/main.go
new file mode 100644
index 0000000..ab8eee4
--- /dev/null
+++ b/code/20919172-2e92-47a9-b4b1-bbce938d0e91/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b+1)
+}
diff --git a/code/286517ab-d294-4b56-b437-044e8e53669f/main.go b/code/286517ab-d294-4b56-b437-044e8e53669f/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/286517ab-d294-4b56-b437-044e8e53669f/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/34ac8555-b79c-4fc3-b888-64b1039b8893/main.go b/code/34ac8555-b79c-4fc3-b888-64b1039b8893/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/34ac8555-b79c-4fc3-b888-64b1039b8893/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/35b30b49-aa22-40c8-b1d8-8a01d4aa8d2e/main.go b/code/35b30b49-aa22-40c8-b1d8-8a01d4aa8d2e/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/35b30b49-aa22-40c8-b1d8-8a01d4aa8d2e/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/3a14b01b-a415-45b2-9f9c-c6a64b2b3019/main.go b/code/3a14b01b-a415-45b2-9f9c-c6a64b2b3019/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/3a14b01b-a415-45b2-9f9c-c6a64b2b3019/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/3c4b47df-7dfe-4155-911a-06128d00a5f3/main.go b/code/3c4b47df-7dfe-4155-911a-06128d00a5f3/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/3c4b47df-7dfe-4155-911a-06128d00a5f3/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/3df4aaa4-2b11-415e-a267-988cf45178e1/main.go b/code/3df4aaa4-2b11-415e-a267-988cf45178e1/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/3df4aaa4-2b11-415e-a267-988cf45178e1/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/3e949edd-caa8-4159-b746-fd8b3c72d963/main.go b/code/3e949edd-caa8-4159-b746-fd8b3c72d963/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/3e949edd-caa8-4159-b746-fd8b3c72d963/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/3fc12ddd-f29d-4070-a663-71b3d98da997/main.go b/code/3fc12ddd-f29d-4070-a663-71b3d98da997/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/3fc12ddd-f29d-4070-a663-71b3d98da997/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/436e15e1-def4-4374-9c2c-a6fd7f6c2f18/main.go b/code/436e15e1-def4-4374-9c2c-a6fd7f6c2f18/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/436e15e1-def4-4374-9c2c-a6fd7f6c2f18/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/4c9a0075-4467-4869-a8c2-6f7991a71c12/main.go b/code/4c9a0075-4467-4869-a8c2-6f7991a71c12/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/4c9a0075-4467-4869-a8c2-6f7991a71c12/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/51763dc6-c29b-4988-ba0c-b50538f0182f/main.go b/code/51763dc6-c29b-4988-ba0c-b50538f0182f/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/51763dc6-c29b-4988-ba0c-b50538f0182f/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/52b02072-e991-4e8d-8070-38f6b75c75a6/main.go b/code/52b02072-e991-4e8d-8070-38f6b75c75a6/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/52b02072-e991-4e8d-8070-38f6b75c75a6/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/611590a5-7457-4d35-b6b6-f63180d833a8/main.go b/code/611590a5-7457-4d35-b6b6-f63180d833a8/main.go
new file mode 100644
index 0000000..ab8eee4
--- /dev/null
+++ b/code/611590a5-7457-4d35-b6b6-f63180d833a8/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b+1)
+}
diff --git a/code/66ab7e0b-50d1-4757-9eeb-94a711f75a56/main.go b/code/66ab7e0b-50d1-4757-9eeb-94a711f75a56/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/66ab7e0b-50d1-4757-9eeb-94a711f75a56/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/6a9f83b9-f907-4586-a455-1fa50651db17/main.go b/code/6a9f83b9-f907-4586-a455-1fa50651db17/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/6a9f83b9-f907-4586-a455-1fa50651db17/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/6e832308-ba23-41f7-9e48-0cc478dbbf04/main.go b/code/6e832308-ba23-41f7-9e48-0cc478dbbf04/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/6e832308-ba23-41f7-9e48-0cc478dbbf04/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/7025963e-8e4a-4a93-90c7-d59d8494ea38/main.go b/code/7025963e-8e4a-4a93-90c7-d59d8494ea38/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/7025963e-8e4a-4a93-90c7-d59d8494ea38/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/73e8bd21-dcca-483a-8224-a023028c6891/main.go b/code/73e8bd21-dcca-483a-8224-a023028c6891/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/73e8bd21-dcca-483a-8224-a023028c6891/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/748ba15f-e625-480a-aed9-5c80ccbc2417/main.go b/code/748ba15f-e625-480a-aed9-5c80ccbc2417/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/748ba15f-e625-480a-aed9-5c80ccbc2417/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/74f14be1-1d7f-4eb6-8bb7-66e0c16422f6/main.go b/code/74f14be1-1d7f-4eb6-8bb7-66e0c16422f6/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/74f14be1-1d7f-4eb6-8bb7-66e0c16422f6/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/79f3a2da-5197-438e-9948-4f3fa05a21f5/main.go b/code/79f3a2da-5197-438e-9948-4f3fa05a21f5/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/79f3a2da-5197-438e-9948-4f3fa05a21f5/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/7b1eb8ac-8fa1-4976-823b-22cd3059e4b8/main.go b/code/7b1eb8ac-8fa1-4976-823b-22cd3059e4b8/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/7b1eb8ac-8fa1-4976-823b-22cd3059e4b8/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/80089deb-ff4c-4b5f-88b7-18973e49e16e/main.go b/code/80089deb-ff4c-4b5f-88b7-18973e49e16e/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/80089deb-ff4c-4b5f-88b7-18973e49e16e/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/87ad3870-15c5-4920-8f78-517ef85c43a7/main.go b/code/87ad3870-15c5-4920-8f78-517ef85c43a7/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/87ad3870-15c5-4920-8f78-517ef85c43a7/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/88c851a8-9add-4f1a-a38e-59ef9d0abf4e/main.go b/code/88c851a8-9add-4f1a-a38e-59ef9d0abf4e/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/88c851a8-9add-4f1a-a38e-59ef9d0abf4e/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/8ff8ecf3-62bf-4fb4-90f3-2ff10916c9d4/main.go b/code/8ff8ecf3-62bf-4fb4-90f3-2ff10916c9d4/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/8ff8ecf3-62bf-4fb4-90f3-2ff10916c9d4/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/95476d8f-99ad-4f8a-8564-aeb2847ca6bb/main.go b/code/95476d8f-99ad-4f8a-8564-aeb2847ca6bb/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/95476d8f-99ad-4f8a-8564-aeb2847ca6bb/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/999030bf-8eb6-4178-adbb-256fab98e796/main.go b/code/999030bf-8eb6-4178-adbb-256fab98e796/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/999030bf-8eb6-4178-adbb-256fab98e796/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/9c7af05b-6a03-4a0a-aeb8-353ea000c435/main.go b/code/9c7af05b-6a03-4a0a-aeb8-353ea000c435/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/9c7af05b-6a03-4a0a-aeb8-353ea000c435/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/9cc60fcb-4401-4bbf-99d2-1337d5133e76/main.go b/code/9cc60fcb-4401-4bbf-99d2-1337d5133e76/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/9cc60fcb-4401-4bbf-99d2-1337d5133e76/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/9e0330fc-c22c-41d8-a197-d476d2f87e84/main.go b/code/9e0330fc-c22c-41d8-a197-d476d2f87e84/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/9e0330fc-c22c-41d8-a197-d476d2f87e84/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/9e495e85-0992-4987-b32c-cfdbe8cee8ba/main.go b/code/9e495e85-0992-4987-b32c-cfdbe8cee8ba/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/9e495e85-0992-4987-b32c-cfdbe8cee8ba/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/a23ba488-f9cc-46de-923a-d113fc5b3f40/main.go b/code/a23ba488-f9cc-46de-923a-d113fc5b3f40/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/a23ba488-f9cc-46de-923a-d113fc5b3f40/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/a381c90d-fc6a-42d8-8e2f-7a502ff2f769/main.go b/code/a381c90d-fc6a-42d8-8e2f-7a502ff2f769/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/a381c90d-fc6a-42d8-8e2f-7a502ff2f769/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/a4a4564b-8599-424c-80da-83c5343d79ea/main.go b/code/a4a4564b-8599-424c-80da-83c5343d79ea/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/a4a4564b-8599-424c-80da-83c5343d79ea/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/ad3d4eb0-7afc-4b70-aa00-991e3da5be2b/main.go b/code/ad3d4eb0-7afc-4b70-aa00-991e3da5be2b/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/ad3d4eb0-7afc-4b70-aa00-991e3da5be2b/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/ad9538b6-0659-4b7a-96c2-3845c6b92fbe/main.go b/code/ad9538b6-0659-4b7a-96c2-3845c6b92fbe/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/ad9538b6-0659-4b7a-96c2-3845c6b92fbe/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/c03c47f7-4069-479a-9fe2-f915473c6997/main.go b/code/c03c47f7-4069-479a-9fe2-f915473c6997/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/c03c47f7-4069-479a-9fe2-f915473c6997/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/c7557548-e675-493d-94c4-73248303a918/main.go b/code/c7557548-e675-493d-94c4-73248303a918/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/c7557548-e675-493d-94c4-73248303a918/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/ca660014-e21a-41b0-b5ac-26ccb88a9c10/main.go b/code/ca660014-e21a-41b0-b5ac-26ccb88a9c10/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/ca660014-e21a-41b0-b5ac-26ccb88a9c10/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/cd4a099d-4f0d-45bc-9028-c601f3de68be/main.go b/code/cd4a099d-4f0d-45bc-9028-c601f3de68be/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/cd4a099d-4f0d-45bc-9028-c601f3de68be/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/code_user/main.go b/code/code_user/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/code_user/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/d7705570-39c9-4776-9ac0-6ff0b24e65a2/main.go b/code/d7705570-39c9-4776-9ac0-6ff0b24e65a2/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/d7705570-39c9-4776-9ac0-6ff0b24e65a2/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/daa08bd4-135f-4dca-a152-6aeb90afa938/main.go b/code/daa08bd4-135f-4dca-a152-6aeb90afa938/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/daa08bd4-135f-4dca-a152-6aeb90afa938/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/db7be0f4-17c2-4aa1-80a9-d45c9bf86da5/main.go b/code/db7be0f4-17c2-4aa1-80a9-d45c9bf86da5/main.go
new file mode 100644
index 0000000..ab8eee4
--- /dev/null
+++ b/code/db7be0f4-17c2-4aa1-80a9-d45c9bf86da5/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b+1)
+}
diff --git a/code/dcd15341-a8d5-4da8-9bfc-0455bc393231/main.go b/code/dcd15341-a8d5-4da8-9bfc-0455bc393231/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/dcd15341-a8d5-4da8-9bfc-0455bc393231/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/e2c24aed-8673-47ea-a93e-f968c88a6efc/main.go b/code/e2c24aed-8673-47ea-a93e-f968c88a6efc/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/e2c24aed-8673-47ea-a93e-f968c88a6efc/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/f8b6272d-d7cf-4d03-b06b-e9a125a8f549/main.go b/code/f8b6272d-d7cf-4d03-b06b-e9a125a8f549/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/f8b6272d-d7cf-4d03-b06b-e9a125a8f549/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/fc328f1d-3859-4a8b-b8e5-572521e4fdfb/main.go b/code/fc328f1d-3859-4a8b-b8e5-572521e4fdfb/main.go
new file mode 100644
index 0000000..9b9e69a
--- /dev/null
+++ b/code/fc328f1d-3859-4a8b-b8e5-572521e4fdfb/main.go
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+// 两数之和
+func main() {
+ var a, b int
+ fmt.Scanln(&a, &b)
+ fmt.Println(a + b)
+}
diff --git a/code/runner.go b/code/runner.go
new file mode 100644
index 0000000..09f4a8f
--- /dev/null
+++ b/code/runner.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "log"
+ "os/exec"
+)
+
+func main() {
+ cmd := exec.Command("go", "run", "C:\\Users\\linshengqian\\Desktop\\gin-gorm-oj\\code\\code_user\\main.go")
+ var out, stderr bytes.Buffer
+ cmd.Stderr = &stderr
+ cmd.Stdout = &out
+ stdinPipe, err := cmd.StdinPipe()
+ if err != nil {
+ log.Fatalln(err)
+ }
+ io.WriteString(stdinPipe, "23 11\n")
+ //根据测试的输入案例进行运行,拿到输出结果和标准输出结果进行比对
+ if err = cmd.Run(); err != nil {
+ log.Fatalln(err)
+ }
+ fmt.Println(out.String())
+
+ println(out.String() == "34\n")
+}
diff --git a/define/define.go b/define/define.go
new file mode 100644
index 0000000..2e9519d
--- /dev/null
+++ b/define/define.go
@@ -0,0 +1,6 @@
+package define
+
+var (
+ DefaultPage = "1" //默认页数
+ DefaultSize = "20"
+)
diff --git a/docs/docs.go b/docs/docs.go
new file mode 100644
index 0000000..23c8248
--- /dev/null
+++ b/docs/docs.go
@@ -0,0 +1,653 @@
+// Package docs Code generated by swaggo/swag. DO NOT EDIT
+package docs
+
+import "github.com/swaggo/swag"
+
+const docTemplate = `{
+ "schemes": {{ marshal .Schemes }},
+ "swagger": "2.0",
+ "info": {
+ "description": "{{escape .Description}}",
+ "title": "{{.Title}}",
+ "contact": {},
+ "version": "{{.Version}}"
+ },
+ "host": "{{.Host}}",
+ "basePath": "{{.BasePath}}",
+ "paths": {
+ "/admin/category_create": {
+ "post": {
+ "tags": [
+ "管理员私有方法"
+ ],
+ "summary": "分类的创建",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "authorization",
+ "name": "authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "name",
+ "name": "name",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "parentId",
+ "name": "parentId",
+ "in": "formData"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/admin/category_delete": {
+ "delete": {
+ "tags": [
+ "管理员私有方法"
+ ],
+ "summary": "分类的删除",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "authorization",
+ "name": "authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "identity",
+ "name": "identity",
+ "in": "query",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"data\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/admin/category_list": {
+ "get": {
+ "tags": [
+ "管理员私有方法"
+ ],
+ "summary": "分类列表",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "authorization",
+ "name": "authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "description": "第一页面",
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "size",
+ "name": "size",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "keyword",
+ "name": "keyword",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/admin/category_modify": {
+ "put": {
+ "tags": [
+ "管理员私有方法"
+ ],
+ "summary": "分类的修改",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "authorization",
+ "name": "authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "identity",
+ "name": "identity",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "name",
+ "name": "name",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "description": "parentId",
+ "name": "parentId",
+ "in": "formData"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"data\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/admin/problem_create": {
+ "post": {
+ "tags": [
+ "管理员私有方法"
+ ],
+ "summary": "问题创建",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "authorization",
+ "name": "authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "title",
+ "name": "title",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "content",
+ "name": "content",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "description": "max_runtime",
+ "name": "max_runtime",
+ "in": "formData"
+ },
+ {
+ "type": "integer",
+ "description": "max_mem",
+ "name": "max_mem",
+ "in": "formData"
+ },
+ {
+ "type": "array",
+ "description": "category_ids",
+ "name": "category_ids",
+ "in": "formData"
+ },
+ {
+ "type": "array",
+ "description": "test_cases",
+ "name": "test_cases",
+ "in": "formData",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/admin/problem_modify": {
+ "put": {
+ "tags": [
+ "管理员私有方法"
+ ],
+ "summary": "问题修改",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "authorization",
+ "name": "authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "identity",
+ "name": "identity",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "title",
+ "name": "title",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "content",
+ "name": "content",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "description": "max_runtime",
+ "name": "max_runtime",
+ "in": "formData"
+ },
+ {
+ "type": "integer",
+ "description": "max_mem",
+ "name": "max_mem",
+ "in": "formData"
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "collectionFormat": "multi",
+ "description": "category_ids",
+ "name": "category_ids",
+ "in": "formData"
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "collectionFormat": "multi",
+ "description": "test_cases",
+ "name": "test_cases",
+ "in": "formData",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/login": {
+ "post": {
+ "tags": [
+ "公共方法"
+ ],
+ "summary": "用户登录",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "username",
+ "name": "username",
+ "in": "formData"
+ },
+ {
+ "type": "string",
+ "description": "password",
+ "name": "password",
+ "in": "formData"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/problem_detail": {
+ "get": {
+ "tags": [
+ "公共方法"
+ ],
+ "summary": "问题详情",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "problem_identity",
+ "name": "identity",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/problem_list": {
+ "get": {
+ "tags": [
+ "公共方法"
+ ],
+ "summary": "问题列表",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "第一页面",
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "size",
+ "name": "size",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "keyword",
+ "name": "keyword",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "category_identity",
+ "name": "category_identity",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/rank_list": {
+ "get": {
+ "tags": [
+ "公共方法"
+ ],
+ "summary": "用户排行榜",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "page",
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "size",
+ "name": "size",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/register": {
+ "post": {
+ "tags": [
+ "公共方法"
+ ],
+ "summary": "用户注册",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "mail",
+ "name": "mail",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "code",
+ "name": "code",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "name",
+ "name": "name",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "password",
+ "name": "password",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "phone",
+ "name": "phone",
+ "in": "formData"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/send_code": {
+ "post": {
+ "tags": [
+ "公共方法"
+ ],
+ "summary": "发送验证码",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "email",
+ "name": "email",
+ "in": "formData"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/submit_list": {
+ "get": {
+ "tags": [
+ "公共方法"
+ ],
+ "summary": "提交列表",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "第一页面",
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "size",
+ "name": "size",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "problem_identity",
+ "name": "problem_identity",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "user_identity",
+ "name": "user_identity",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "status",
+ "name": "status",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/user/submit": {
+ "post": {
+ "tags": [
+ "用户私有方法"
+ ],
+ "summary": "代码提交",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "authorization",
+ "name": "authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "problem_identity",
+ "name": "problem_identity",
+ "in": "query",
+ "required": true
+ },
+ {
+ "description": "code",
+ "name": "code",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"data\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/user_detail": {
+ "get": {
+ "tags": [
+ "公共方法"
+ ],
+ "summary": "用户详情",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "problem_identity",
+ "name": "identity",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+}`
+
+// SwaggerInfo holds exported Swagger Info so clients can modify it
+var SwaggerInfo = &swag.Spec{
+ Version: "",
+ Host: "",
+ BasePath: "",
+ Schemes: []string{},
+ Title: "",
+ Description: "",
+ InfoInstanceName: "swagger",
+ SwaggerTemplate: docTemplate,
+ LeftDelim: "{{",
+ RightDelim: "}}",
+}
+
+func init() {
+ swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
+}
diff --git a/docs/swagger.json b/docs/swagger.json
new file mode 100644
index 0000000..a7c1b89
--- /dev/null
+++ b/docs/swagger.json
@@ -0,0 +1,624 @@
+{
+ "swagger": "2.0",
+ "info": {
+ "contact": {}
+ },
+ "paths": {
+ "/admin/category_create": {
+ "post": {
+ "tags": [
+ "管理员私有方法"
+ ],
+ "summary": "分类的创建",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "authorization",
+ "name": "authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "name",
+ "name": "name",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "parentId",
+ "name": "parentId",
+ "in": "formData"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/admin/category_delete": {
+ "delete": {
+ "tags": [
+ "管理员私有方法"
+ ],
+ "summary": "分类的删除",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "authorization",
+ "name": "authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "identity",
+ "name": "identity",
+ "in": "query",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"data\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/admin/category_list": {
+ "get": {
+ "tags": [
+ "管理员私有方法"
+ ],
+ "summary": "分类列表",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "authorization",
+ "name": "authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "description": "第一页面",
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "size",
+ "name": "size",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "keyword",
+ "name": "keyword",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/admin/category_modify": {
+ "put": {
+ "tags": [
+ "管理员私有方法"
+ ],
+ "summary": "分类的修改",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "authorization",
+ "name": "authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "identity",
+ "name": "identity",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "name",
+ "name": "name",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "description": "parentId",
+ "name": "parentId",
+ "in": "formData"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"data\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/admin/problem_create": {
+ "post": {
+ "tags": [
+ "管理员私有方法"
+ ],
+ "summary": "问题创建",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "authorization",
+ "name": "authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "title",
+ "name": "title",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "content",
+ "name": "content",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "description": "max_runtime",
+ "name": "max_runtime",
+ "in": "formData"
+ },
+ {
+ "type": "integer",
+ "description": "max_mem",
+ "name": "max_mem",
+ "in": "formData"
+ },
+ {
+ "type": "array",
+ "description": "category_ids",
+ "name": "category_ids",
+ "in": "formData"
+ },
+ {
+ "type": "array",
+ "description": "test_cases",
+ "name": "test_cases",
+ "in": "formData",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/admin/problem_modify": {
+ "put": {
+ "tags": [
+ "管理员私有方法"
+ ],
+ "summary": "问题修改",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "authorization",
+ "name": "authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "identity",
+ "name": "identity",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "title",
+ "name": "title",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "content",
+ "name": "content",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "description": "max_runtime",
+ "name": "max_runtime",
+ "in": "formData"
+ },
+ {
+ "type": "integer",
+ "description": "max_mem",
+ "name": "max_mem",
+ "in": "formData"
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "collectionFormat": "multi",
+ "description": "category_ids",
+ "name": "category_ids",
+ "in": "formData"
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "collectionFormat": "multi",
+ "description": "test_cases",
+ "name": "test_cases",
+ "in": "formData",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/login": {
+ "post": {
+ "tags": [
+ "公共方法"
+ ],
+ "summary": "用户登录",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "username",
+ "name": "username",
+ "in": "formData"
+ },
+ {
+ "type": "string",
+ "description": "password",
+ "name": "password",
+ "in": "formData"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/problem_detail": {
+ "get": {
+ "tags": [
+ "公共方法"
+ ],
+ "summary": "问题详情",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "problem_identity",
+ "name": "identity",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/problem_list": {
+ "get": {
+ "tags": [
+ "公共方法"
+ ],
+ "summary": "问题列表",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "第一页面",
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "size",
+ "name": "size",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "keyword",
+ "name": "keyword",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "category_identity",
+ "name": "category_identity",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/rank_list": {
+ "get": {
+ "tags": [
+ "公共方法"
+ ],
+ "summary": "用户排行榜",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "page",
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "size",
+ "name": "size",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/register": {
+ "post": {
+ "tags": [
+ "公共方法"
+ ],
+ "summary": "用户注册",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "mail",
+ "name": "mail",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "code",
+ "name": "code",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "name",
+ "name": "name",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "password",
+ "name": "password",
+ "in": "formData",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "phone",
+ "name": "phone",
+ "in": "formData"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/send_code": {
+ "post": {
+ "tags": [
+ "公共方法"
+ ],
+ "summary": "发送验证码",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "email",
+ "name": "email",
+ "in": "formData"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/submit_list": {
+ "get": {
+ "tags": [
+ "公共方法"
+ ],
+ "summary": "提交列表",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "第一页面",
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "size",
+ "name": "size",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "problem_identity",
+ "name": "problem_identity",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "user_identity",
+ "name": "user_identity",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "status",
+ "name": "status",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/user/submit": {
+ "post": {
+ "tags": [
+ "用户私有方法"
+ ],
+ "summary": "代码提交",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "authorization",
+ "name": "authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "problem_identity",
+ "name": "problem_identity",
+ "in": "query",
+ "required": true
+ },
+ {
+ "description": "code",
+ "name": "code",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"data\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "/user_detail": {
+ "get": {
+ "tags": [
+ "公共方法"
+ ],
+ "summary": "用户详情",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "problem_identity",
+ "name": "identity",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "{\"code\":\"200\",\"list\":\"\"}",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
new file mode 100644
index 0000000..2a05252
--- /dev/null
+++ b/docs/swagger.yaml
@@ -0,0 +1,408 @@
+info:
+ contact: {}
+paths:
+ /admin/category_create:
+ post:
+ parameters:
+ - description: authorization
+ in: header
+ name: authorization
+ required: true
+ type: string
+ - description: name
+ in: formData
+ name: name
+ required: true
+ type: string
+ - description: parentId
+ in: formData
+ name: parentId
+ type: string
+ responses:
+ "200":
+ description: '{"code":"200","list":""}'
+ schema:
+ type: string
+ summary: 分类的创建
+ tags:
+ - 管理员私有方法
+ /admin/category_delete:
+ delete:
+ parameters:
+ - description: authorization
+ in: header
+ name: authorization
+ required: true
+ type: string
+ - description: identity
+ in: query
+ name: identity
+ required: true
+ type: string
+ responses:
+ "200":
+ description: '{"code":"200","data":""}'
+ schema:
+ type: string
+ summary: 分类的删除
+ tags:
+ - 管理员私有方法
+ /admin/category_list:
+ get:
+ parameters:
+ - description: authorization
+ in: header
+ name: authorization
+ required: true
+ type: string
+ - description: 第一页面
+ in: query
+ name: page
+ type: integer
+ - description: size
+ in: query
+ name: size
+ type: integer
+ - description: keyword
+ in: query
+ name: keyword
+ type: string
+ responses:
+ "200":
+ description: '{"code":"200","list":""}'
+ schema:
+ type: string
+ summary: 分类列表
+ tags:
+ - 管理员私有方法
+ /admin/category_modify:
+ put:
+ parameters:
+ - description: authorization
+ in: header
+ name: authorization
+ required: true
+ type: string
+ - description: identity
+ in: formData
+ name: identity
+ required: true
+ type: string
+ - description: name
+ in: formData
+ name: name
+ required: true
+ type: string
+ - description: parentId
+ in: formData
+ name: parentId
+ type: integer
+ responses:
+ "200":
+ description: '{"code":"200","data":""}'
+ schema:
+ type: string
+ summary: 分类的修改
+ tags:
+ - 管理员私有方法
+ /admin/problem_create:
+ post:
+ parameters:
+ - description: authorization
+ in: header
+ name: authorization
+ required: true
+ type: string
+ - description: title
+ in: formData
+ name: title
+ required: true
+ type: string
+ - description: content
+ in: formData
+ name: content
+ required: true
+ type: string
+ - description: max_runtime
+ in: formData
+ name: max_runtime
+ type: integer
+ - description: max_mem
+ in: formData
+ name: max_mem
+ type: integer
+ - description: category_ids
+ in: formData
+ name: category_ids
+ type: array
+ - description: test_cases
+ in: formData
+ name: test_cases
+ required: true
+ type: array
+ responses:
+ "200":
+ description: '{"code":"200","list":""}'
+ schema:
+ type: string
+ summary: 问题创建
+ tags:
+ - 管理员私有方法
+ /admin/problem_modify:
+ put:
+ parameters:
+ - description: authorization
+ in: header
+ name: authorization
+ required: true
+ type: string
+ - description: identity
+ in: formData
+ name: identity
+ required: true
+ type: string
+ - description: title
+ in: formData
+ name: title
+ required: true
+ type: string
+ - description: content
+ in: formData
+ name: content
+ required: true
+ type: string
+ - description: max_runtime
+ in: formData
+ name: max_runtime
+ type: integer
+ - description: max_mem
+ in: formData
+ name: max_mem
+ type: integer
+ - collectionFormat: multi
+ description: category_ids
+ in: formData
+ items:
+ type: string
+ name: category_ids
+ type: array
+ - collectionFormat: multi
+ description: test_cases
+ in: formData
+ items:
+ type: string
+ name: test_cases
+ required: true
+ type: array
+ responses:
+ "200":
+ description: '{"code":"200","list":""}'
+ schema:
+ type: string
+ summary: 问题修改
+ tags:
+ - 管理员私有方法
+ /login:
+ post:
+ parameters:
+ - description: username
+ in: formData
+ name: username
+ type: string
+ - description: password
+ in: formData
+ name: password
+ type: string
+ responses:
+ "200":
+ description: '{"code":"200","list":""}'
+ schema:
+ type: string
+ summary: 用户登录
+ tags:
+ - 公共方法
+ /problem_detail:
+ get:
+ parameters:
+ - description: problem_identity
+ in: query
+ name: identity
+ type: string
+ responses:
+ "200":
+ description: '{"code":"200","list":""}'
+ schema:
+ type: string
+ summary: 问题详情
+ tags:
+ - 公共方法
+ /problem_list:
+ get:
+ parameters:
+ - description: 第一页面
+ in: query
+ name: page
+ type: integer
+ - description: size
+ in: query
+ name: size
+ type: integer
+ - description: keyword
+ in: query
+ name: keyword
+ type: string
+ - description: category_identity
+ in: query
+ name: category_identity
+ type: string
+ responses:
+ "200":
+ description: '{"code":"200","list":""}'
+ schema:
+ type: string
+ summary: 问题列表
+ tags:
+ - 公共方法
+ /rank_list:
+ get:
+ parameters:
+ - description: page
+ in: query
+ name: page
+ type: string
+ - description: size
+ in: query
+ name: size
+ type: string
+ responses:
+ "200":
+ description: '{"code":"200","list":""}'
+ schema:
+ type: string
+ summary: 用户排行榜
+ tags:
+ - 公共方法
+ /register:
+ post:
+ parameters:
+ - description: mail
+ in: formData
+ name: mail
+ required: true
+ type: string
+ - description: code
+ in: formData
+ name: code
+ required: true
+ type: string
+ - description: name
+ in: formData
+ name: name
+ required: true
+ type: string
+ - description: password
+ in: formData
+ name: password
+ required: true
+ type: string
+ - description: phone
+ in: formData
+ name: phone
+ type: string
+ responses:
+ "200":
+ description: '{"code":"200","list":""}'
+ schema:
+ type: string
+ summary: 用户注册
+ tags:
+ - 公共方法
+ /send_code:
+ post:
+ parameters:
+ - description: email
+ in: formData
+ name: email
+ type: string
+ responses:
+ "200":
+ description: '{"code":"200","list":""}'
+ schema:
+ type: string
+ summary: 发送验证码
+ tags:
+ - 公共方法
+ /submit_list:
+ get:
+ parameters:
+ - description: 第一页面
+ in: query
+ name: page
+ type: integer
+ - description: size
+ in: query
+ name: size
+ type: integer
+ - description: problem_identity
+ in: query
+ name: problem_identity
+ type: string
+ - description: user_identity
+ in: query
+ name: user_identity
+ type: string
+ - description: status
+ in: query
+ name: status
+ type: integer
+ responses:
+ "200":
+ description: '{"code":"200","list":""}'
+ schema:
+ type: string
+ summary: 提交列表
+ tags:
+ - 公共方法
+ /user/submit:
+ post:
+ parameters:
+ - description: authorization
+ in: header
+ name: authorization
+ required: true
+ type: string
+ - description: problem_identity
+ in: query
+ name: problem_identity
+ required: true
+ type: string
+ - description: code
+ in: body
+ name: code
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: '{"code":"200","data":""}'
+ schema:
+ type: string
+ summary: 代码提交
+ tags:
+ - 用户私有方法
+ /user_detail:
+ get:
+ parameters:
+ - description: problem_identity
+ in: query
+ name: identity
+ type: string
+ responses:
+ "200":
+ description: '{"code":"200","list":""}'
+ schema:
+ type: string
+ summary: 用户详情
+ tags:
+ - 公共方法
+swagger: "2.0"
diff --git a/gin-gorm-oj b/gin-gorm-oj
new file mode 160000
index 0000000..56b53c3
--- /dev/null
+++ b/gin-gorm-oj
@@ -0,0 +1 @@
+Subproject commit 56b53c301f1f5f8054b17595bfbce3071a058540
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..e67a869
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,59 @@
+module lsq.com
+
+go 1.21
+
+require (
+ github.com/gin-gonic/gin v1.9.1
+ github.com/golang-jwt/jwt/v4 v4.5.0
+ github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
+ github.com/swaggo/files v1.0.1
+ github.com/swaggo/gin-swagger v1.6.0
+ github.com/swaggo/swag v1.16.3
+ gorm.io/driver/mysql v1.5.6
+ gorm.io/gorm v1.25.9
+)
+
+require (
+ filippo.io/edwards25519 v1.1.0 // indirect
+ github.com/KyleBanks/depth v1.2.1 // indirect
+ github.com/bytedance/sonic v1.11.3 // indirect
+ github.com/cespare/xxhash/v2 v2.2.0 // indirect
+ github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
+ github.com/chenzhuoyu/iasm v0.9.1 // indirect
+ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
+ github.com/gabriel-vasile/mimetype v1.4.3 // indirect
+ github.com/gin-contrib/sse v0.1.0 // indirect
+ github.com/go-openapi/jsonpointer v0.21.0 // indirect
+ github.com/go-openapi/jsonreference v0.21.0 // indirect
+ github.com/go-openapi/spec v0.21.0 // indirect
+ github.com/go-openapi/swag v0.23.0 // indirect
+ github.com/go-playground/locales v0.14.1 // indirect
+ github.com/go-playground/universal-translator v0.18.1 // indirect
+ github.com/go-playground/validator/v10 v10.19.0 // indirect
+ github.com/go-sql-driver/mysql v1.8.1 // indirect
+ github.com/goccy/go-json v0.10.2 // indirect
+ github.com/google/go-cmp v0.5.9 // indirect
+ github.com/jinzhu/inflection v1.0.0 // indirect
+ github.com/jinzhu/now v1.1.5 // indirect
+ github.com/josharian/intern v1.0.0 // indirect
+ github.com/json-iterator/go v1.1.12 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.7 // indirect
+ github.com/leodido/go-urn v1.4.0 // indirect
+ github.com/mailru/easyjson v0.7.7 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+ github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/pelletier/go-toml/v2 v2.2.0 // indirect
+ github.com/redis/go-redis/v9 v9.5.1 // indirect
+ github.com/satori/go.uuid v1.2.0 // indirect
+ github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
+ github.com/ugorji/go/codec v1.2.12 // indirect
+ golang.org/x/arch v0.7.0 // indirect
+ golang.org/x/crypto v0.21.0 // indirect
+ golang.org/x/net v0.22.0 // indirect
+ golang.org/x/sys v0.18.0 // indirect
+ golang.org/x/text v0.14.0 // indirect
+ golang.org/x/tools v0.19.0 // indirect
+ google.golang.org/protobuf v1.33.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..dc10cd4
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,175 @@
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
+github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
+github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
+github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
+github.com/bytedance/sonic v1.11.3 h1:jRN+yEjakWh8aK5FzrciUHG8OFXK+4/KrAX/ysEtHAA=
+github.com/bytedance/sonic v1.11.3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
+github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
+github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
+github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
+github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
+github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
+github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
+github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
+github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
+github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
+github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
+github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
+github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
+github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
+github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
+github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
+github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
+github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
+github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
+github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
+github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
+github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
+github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
+github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
+github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
+github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
+github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
+github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
+github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4=
+github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
+github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
+github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
+github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
+github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
+github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
+github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
+github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
+github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA=
+github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
+github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
+github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo=
+github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8=
+github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
+github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
+github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
+github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
+github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
+github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
+github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
+github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
+github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
+github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
+github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
+github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
+github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
+golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
+golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
+golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
+golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
+golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
+golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8=
+gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
+gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
+gorm.io/gorm v1.25.9 h1:wct0gxZIELDk8+ZqF/MVnHLkA1rvYlBWUMv2EdsK1g8=
+gorm.io/gorm v1.25.9/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
+nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
diff --git a/helper/helper.go b/helper/helper.go
new file mode 100644
index 0000000..a53b4d3
--- /dev/null
+++ b/helper/helper.go
@@ -0,0 +1,115 @@
+package helper
+
+import (
+ "crypto/md5"
+ "fmt"
+ "github.com/golang-jwt/jwt/v4"
+ "github.com/jordan-wright/email"
+ uuid "github.com/satori/go.uuid"
+ "math/rand"
+ "net/smtp"
+ "os"
+ "strconv"
+ "time"
+)
+
+type UserClaims struct {
+ Identity string `json:"identity"`
+ Name string `json:"name"`
+ IsAdmin int `json:"is_admin"`
+ jwt.StandardClaims
+}
+
+func GetMd5(s string) string {
+ return fmt.Sprintf("%x", md5.Sum([]byte(s)))
+}
+
+// TODO 签名密钥
+var myKey = []byte("gin-gorm-oj-key")
+
+// GenerateToken
+// TODO 生成token
+func GenerateToken(identity, name string, isAdmin int) (string, error) {
+ UserClaims := &UserClaims{
+ Identity: "user_1",
+ Name: "get",
+ IsAdmin: isAdmin,
+ StandardClaims: jwt.StandardClaims{
+ //NotBefore: time.Now().Unix() - 60, // 令牌在当前时间的前60秒之前不生效
+ //ExpiresAt: time.Now().Unix() + 5, // 令牌将在当前时间的后5秒过期
+ Issuer: "lsq", // 令牌的发行者
+ },
+ }
+ //TODO 使用指定的签名方法和声明创建一个新的令牌
+ token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaims)
+ //TODO 使用签名密钥对令牌进行签名,并获取完整的签名后的令牌字符串
+ tokenString, err := token.SignedString(myKey)
+ if err != nil {
+ return "", err
+ }
+ fmt.Println(tokenString)
+ return tokenString, nil
+ //eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6InVzZXJfMSIsIm5hbWUiOiJnZXQifQ.taKAmMZu6-6ioE4hSKqUgn9lHrqXSw-2TyEQTeNOreA
+}
+
+// AnalyseToken
+// 解析 token
+func AnalyseToken(tokenString string) (*UserClaims, error) {
+ userClaim := new(UserClaims)
+ claims, err := jwt.ParseWithClaims(tokenString, userClaim, func(token *jwt.Token) (interface{}, error) {
+ return myKey, nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ if !claims.Valid {
+ return nil, fmt.Errorf("analyse Token Error:%v", err)
+ }
+ fmt.Println(claims)
+ return userClaim, nil
+}
+
+// SendCode
+// 发送验证码
+func SendCode(toUserEmail, code string) error {
+ e := email.NewEmail()
+ e.From = "Crayon <2993373191@qq.com>"
+ e.To = []string{toUserEmail}
+ e.Subject = "验证码已发送,请查收"
+
+ e.HTML = []byte("
验证码:
" + code)
+ return e.Send("smtp.qq.com:587", smtp.PlainAuth("", "2993373191@qq.com", "vlkrwkqjayqedehc", "smtp.qq.com"))
+}
+
+// GetUUID
+func GetUUID() string {
+ return uuid.NewV4().String()
+}
+
+// 生成验证码
+func GetRand() string {
+ rand.Seed(time.Now().UnixNano())
+ s := ""
+ for i := 0; i < 6; i++ {
+ s += strconv.Itoa(rand.Intn(10))
+ }
+ return s
+}
+
+// CodeSave
+// 保存代码
+func CodeSave(code []byte) (string, error) {
+ dirName := "code/" + GetUUID()
+ path := dirName + "/main.go"
+ err := os.Mkdir(dirName, 0777)
+ if err != nil {
+ return "", err
+ }
+ f, err := os.Create(path)
+ if err != nil {
+ return "", err
+ }
+ f.Write(code)
+ defer f.Close()
+ return path, nil
+}
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..60765a3
--- /dev/null
+++ b/main.go
@@ -0,0 +1,9 @@
+package main
+
+import "lsq.com/router"
+
+func main() {
+ r := router.Router()
+
+ r.Run()
+}
diff --git a/middlewares/auth_admin.go b/middlewares/auth_admin.go
new file mode 100644
index 0000000..bac6bdd
--- /dev/null
+++ b/middlewares/auth_admin.go
@@ -0,0 +1,32 @@
+package middlewares
+
+import (
+ "github.com/gin-gonic/gin"
+ "lsq.com/helper"
+ "net/http"
+)
+
+// AuthAdminCheck 验证用户是否是管理员
+func AuthAdminCheck() gin.HandlerFunc {
+ return func(c *gin.Context) {
+ auth := c.GetHeader("Authorization")
+ userClaim, err := helper.AnalyseToken(auth)
+ if err != nil {
+ c.Abort()
+ c.JSON(http.StatusOK, gin.H{
+ "code": http.StatusUnauthorized,
+ "msg": "Unauthorized Authorization",
+ })
+ return
+ }
+ if userClaim == nil || userClaim.IsAdmin != 1 {
+ c.Abort()
+ c.JSON(http.StatusOK, gin.H{
+ "code": http.StatusUnauthorized,
+ "msg": "Unauthorized Admin",
+ })
+ return
+ }
+ c.Next()
+ }
+}
diff --git a/middlewares/auth_user.go b/middlewares/auth_user.go
new file mode 100644
index 0000000..9363717
--- /dev/null
+++ b/middlewares/auth_user.go
@@ -0,0 +1,35 @@
+package middlewares
+
+import (
+ "fmt"
+ "github.com/gin-gonic/gin"
+ "lsq.com/helper"
+ "net/http"
+)
+
+// AuthUserCheck
+func AuthUserCheck() gin.HandlerFunc {
+ return func(c *gin.Context) {
+ auth := c.GetHeader("Authorization")
+ userClaim, err := helper.AnalyseToken(auth)
+ if err != nil {
+ c.Abort()
+ c.JSON(http.StatusOK, gin.H{
+ "code": http.StatusUnauthorized,
+ "msg": "Unauthorized Authorization",
+ })
+ return
+ }
+ if userClaim == nil {
+ c.Abort()
+ c.JSON(http.StatusOK, gin.H{
+ "code": http.StatusUnauthorized,
+ "msg": "Unauthorized Admin",
+ })
+ return
+ }
+ fmt.Println(userClaim)
+ c.Set("user_claims", userClaim)
+ c.Next()
+ }
+}
diff --git a/models/category_basic.go b/models/category_basic.go
new file mode 100644
index 0000000..8b08af6
--- /dev/null
+++ b/models/category_basic.go
@@ -0,0 +1,16 @@
+package models
+
+import (
+ "gorm.io/gorm"
+)
+
+type CategoryBasic struct {
+ gorm.Model
+ Identity string `gorm:"column:identity;type:varchar(36);" json:"identity"` //分类表的唯一标识
+ Name string `gorm:"column:name;type:varchar(100);" json:"name"` //分类名称
+ ParentId int `gorm:"column:parent_id;type:int(11);" json:"parent_id"` //父类ID
+}
+
+func (table *CategoryBasic) TableName() string {
+ return "category_basic"
+}
diff --git a/models/init.go b/models/init.go
new file mode 100644
index 0000000..84fdd33
--- /dev/null
+++ b/models/init.go
@@ -0,0 +1,28 @@
+package models
+
+import (
+ "github.com/redis/go-redis/v9"
+ "gorm.io/driver/mysql"
+ "gorm.io/gorm"
+ "log"
+)
+
+var DB = Init()
+var RDB = InitRedisDB()
+
+func Init() *gorm.DB {
+ dsn := "root:root@tcp(127.0.0.1:3306)/gin_gorm_oj?charset=utf8mb4&parseTime=True&loc=Local"
+ db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
+ if err != nil {
+ log.Println("gorm Init Error", err)
+ }
+ return db
+}
+func InitRedisDB() *redis.Client {
+ return redis.NewClient(&redis.Options{
+ Addr: "127.0.0.1:6379",
+ Password: "", // no password set
+ DB: 0, // use default DB
+ })
+
+}
diff --git a/models/problem_basic.go b/models/problem_basic.go
new file mode 100644
index 0000000..d083bb2
--- /dev/null
+++ b/models/problem_basic.go
@@ -0,0 +1,33 @@
+package models
+
+import (
+ "gorm.io/gorm"
+)
+
+type ProblemBasic struct {
+ gorm.Model
+ Identity string `gorm:"column:identity;type:varchar(36);" json:"identity"` //问题表的唯一标识
+ ProblemCategories []*ProblemCategory `gorm:"foreignKey:problem_id;references:id"` //关联问题分类表
+ Title string `gorm:"column:title;type:varchar(255);" json:"title"` //文章标题
+ Content string `gorm:"column:content;type:text;" json:"content"` //文章正文
+ MaxRuntime int `gorm:"column:max_runtime;type:int(11);" json:"max_runtime"` //最大运行时间
+ MaxMem int `gorm:"column:max_mem;type:int(11);" json:"max_mem"` //最大内存
+ TestCase []*TestCase `gorm:"foreignKey:problem_identity;references:identity"`
+ PassNum int64 `gorm:"column:pass_num;type:int(11);" json:"pass_num"` //完成问题的个数
+ SubmitNum int64 `gorm:"column:submit_num;type:int(11);" json:"submit_num"` //提交次数
+
+}
+
+func (table *ProblemBasic) TableName() string {
+ return "problem_basic"
+}
+func GetProblemList(keyword, categoryIdentity string) *gorm.DB {
+ //指定查询的表 ,new(Problem)创建Problem模型实例
+ tx := DB.Model(new(ProblemBasic)).Preload("ProblemCategories").Preload("ProblemCategories.CategoryBasic").
+ Where("title like ? OR content like ?", "%"+keyword+"%", "%"+keyword+"%")
+ if categoryIdentity != "" {
+ tx.Joins("RIGHT JOIN problem_category pc on pc.problem_id=problem_basic.id").
+ Where("pc.category_id =(SELECT cb.id FROM category_basic cb WHERE cb.identity=?)", categoryIdentity)
+ }
+ return tx
+}
diff --git a/models/problem_category.go b/models/problem_category.go
new file mode 100644
index 0000000..6e3ea32
--- /dev/null
+++ b/models/problem_category.go
@@ -0,0 +1,16 @@
+package models
+
+import (
+ "gorm.io/gorm"
+)
+
+type ProblemCategory struct {
+ gorm.Model
+ ProblemId uint `gorm:"column:problem_id;type:varchar(36);" json:"problem_id"` // 问题的ID
+ CategoryId uint `gorm:"column:category_id;type:varchar(36);" json:"category_id"` // 分类的ID
+ CategoryBasic *CategoryBasic `gorm:"foreignKey:id;references:category_id;" json:"category_basic"` // 关联分类的基础信息表
+}
+
+func (table *ProblemCategory) TableName() string {
+ return "problem_category"
+}
diff --git a/models/submit_basic.go b/models/submit_basic.go
new file mode 100644
index 0000000..2a47a04
--- /dev/null
+++ b/models/submit_basic.go
@@ -0,0 +1,35 @@
+package models
+
+import "gorm.io/gorm"
+
+type SubmitBasic struct {
+ gorm.Model
+ Identity string `gorm:"column:identity;type:varchar(36);" json:"identity"` //提交表的唯一标识
+ ProblemIdentity string `gorm:"column:problem_identity;type:varchar(36);" json:"problem_identity"` //问题表的唯一标识
+ ProblemBasic *ProblemBasic `gorm:"foreignKey:identity;references:problem_identity"` //关联问题基础表
+ UserIdentity string `gorm:"column:user_identity;type:varchar(32);" json:"user_identity"` //用户表的唯一标识密码
+ UserBasic *UserBasic `gorm:"foreignKey:identity;references:user_identity"` //关联用户基础表
+ Path string `gorm:"column:path;type:varchar(255);" json:"path"` //代码存放路径
+ Status int `gorm:"column:status;type:tinyint(1);" json:"status"` //[-1-待判断,1-答案正确,2-答案错误,3-运行超时,4-运行超内存,5-编译错误]
+}
+
+func (table *SubmitBasic) TableName() string {
+ return "submit_basic"
+}
+
+func GetSubmitList(problemIdentity, userIdentity string, status int) *gorm.DB {
+ //Model(new(SubmitBasic))指定了查询操作的目标模型为 SubmitBasic
+ tx := DB.Model(new(SubmitBasic)).Preload("ProblemBasic", func(db *gorm.DB) *gorm.DB {
+ return db.Omit("content")
+ }).Preload("UserBasic")
+ if problemIdentity != "" {
+ tx.Where("problem_identity=?", problemIdentity)
+ }
+ if userIdentity != "" {
+ tx.Where("user_identity=?", userIdentity)
+ }
+ if status != 0 {
+ tx.Where("status=?", status)
+ }
+ return tx
+}
diff --git a/models/test_case.go b/models/test_case.go
new file mode 100644
index 0000000..1462653
--- /dev/null
+++ b/models/test_case.go
@@ -0,0 +1,15 @@
+package models
+
+import "gorm.io/gorm"
+
+type TestCase struct {
+ gorm.Model
+ Identity string `gorm:"column:identity;type:varchar(36);" json:"identity"` //用户表的唯一标识
+ ProblemIdentity string `gorm:"column:problem_identity;type:varchar(36);" json:"problem_identity"` //用户名
+ Input string `gorm:"column:input;type:text;" json:"input"` //密码
+ Output string `gorm:"column:output;type:text;" json:"output"`
+}
+
+func (table *TestCase) TableName() string {
+ return "test_case"
+}
diff --git a/models/user_basic.go b/models/user_basic.go
new file mode 100644
index 0000000..cd6dbab
--- /dev/null
+++ b/models/user_basic.go
@@ -0,0 +1,21 @@
+package models
+
+import (
+ "gorm.io/gorm"
+)
+
+type UserBasic struct {
+ gorm.Model
+ Identity string `gorm:"column:identity;type:varchar(36);" json:"identity"` //用户表的唯一标识
+ Name string `gorm:"column:name;type:varchar(100);" json:"name"` //用户名
+ Password string `gorm:"column:password;type:varchar(32);" json:"password"` //密码
+ Phone string `gorm:"column:phone;type:varchar(20);" json:"phone"` //手机号
+ Mail string `gorm:"column:mail;type:varchar(100);" json:"mail"` //邮箱
+ PassNum int64 `gorm:"column:pass_num;type:int(11);" json:"pass_num"` //完成问题的个数
+ SubmitNum int64 `gorm:"column:submit_num;type:int(11);" json:"submit_num"` //提交次数
+ IsAdmin int `gorm:"column:is_admin;type:tinyint(1);" json:"is_admin"` //是否是管理员[0不是,1是]
+}
+
+func (table *UserBasic) TableName() string {
+ return "user_basic"
+}
diff --git a/router/app.go b/router/app.go
new file mode 100644
index 0000000..c6d7dea
--- /dev/null
+++ b/router/app.go
@@ -0,0 +1,56 @@
+package router
+
+import (
+ "github.com/gin-gonic/gin"
+ swaggerfiles "github.com/swaggo/files"
+ ginSwagger "github.com/swaggo/gin-swagger"
+ _ "lsq.com/docs"
+ "lsq.com/middlewares"
+ "lsq.com/service"
+)
+
+func Router() *gin.Engine {
+ r := gin.Default()
+
+ //swag 配置
+ r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler))
+
+ //公有方法
+ //问题
+ r.GET("/problem_list", service.GetProblemList)
+ r.GET("/problem_detail", service.GetProblemDetail)
+
+ //用户
+ r.GET("/user_detail", service.GetUserDetailAll)
+ r.POST("/login", service.Login)
+ r.POST("/send_code", service.SendCode)
+ r.POST("/register", service.Register)
+ //用户排行榜
+ r.GET("/rank_list", service.GetRankList)
+
+ //提交记录
+ r.GET("/submit_list", service.GetSubmitList)
+
+ //管理员私有方法
+ authAdmin := r.Group("/admin", middlewares.AuthAdminCheck())
+ //问题创建
+ authAdmin.POST("/problem_create", service.ProblemCreate)
+ //问题修改
+ authAdmin.PUT("/problem_modify", service.ProblemModify)
+ //分类列表
+ authAdmin.GET("/category_list", service.GetCategoryList)
+ //分类的创建
+ authAdmin.POST("/category_create", service.GetCategoryCreate)
+ //分类的修改
+ authAdmin.PUT("/category_modify", service.GetCategoryModify)
+ //分类的删除
+ authAdmin.DELETE("/category_delete", service.GetCategoryDelete)
+
+ //用户私有方法
+ authUser := r.Group("/user", middlewares.AuthUserCheck())
+ //代码提交
+ authUser.POST("/submit", service.Submit)
+
+ return r
+
+}
diff --git a/service/category.go b/service/category.go
new file mode 100644
index 0000000..d18f93b
--- /dev/null
+++ b/service/category.go
@@ -0,0 +1,170 @@
+package service
+
+import (
+ "github.com/gin-gonic/gin"
+ "log"
+ "lsq.com/define"
+ "lsq.com/helper"
+ "lsq.com/models"
+ "net/http"
+ "strconv"
+)
+
+// GetCategoryList
+// @Tags 管理员私有方法
+// @Summary 分类列表
+// @Param authorization header string true "authorization"
+// @Param page query int false "第一页面"
+// @Param size query int false "size"
+// @Param keyword query string false "keyword"
+// @Success 200 {string} json "{"code":"200","list":""}"
+// @Router /admin/category_list [get]
+func GetCategoryList(c *gin.Context) {
+ size, _ := strconv.Atoi(c.DefaultQuery("size", define.DefaultSize))
+ page, err := strconv.Atoi(c.DefaultQuery("page", define.DefaultPage))
+ if err != nil {
+ log.Println("Get ProblemList Page strconv Error:", err)
+ return
+ }
+ //page == 1 ===> offset 0
+ page = (page - 1) * size
+ var count int64
+ keyword := c.Query("keyword")
+ categoryList := make([]*models.CategoryBasic, 0)
+ err = models.DB.Model(new(models.CategoryBasic)).Where("name like ?", "%"+keyword+"%").
+ Count(&count).Limit(size).Offset(page).Find(&categoryList).Error
+ if err != nil {
+ log.Println("GetCategoryList Error:", err)
+ c.JSON(http.StatusOK, gin.H{
+ "code": 200,
+ "msg": "获取分类列表失败",
+ })
+ return
+ }
+ c.JSON(http.StatusOK, gin.H{
+ "code": 200,
+ "data": map[string]interface{}{
+ "list": categoryList,
+ "count": count,
+ },
+ })
+}
+
+// GetCategoryCreate
+// @Tags 管理员私有方法
+// @Summary 分类的创建
+// @Param authorization header string true "authorization"
+// @Param name formData string true "name"
+// @Param parentId formData string false "parentId"
+// @Success 200 {string} json "{"code":"200","list":""}"
+// @Router /admin/category_create [post]
+func GetCategoryCreate(c *gin.Context) {
+ name := c.PostForm("name")
+ parentId, _ := strconv.Atoi(c.PostForm("parentId"))
+ category := &models.CategoryBasic{
+ Identity: helper.GetUUID(),
+ Name: name,
+ ParentId: parentId,
+ }
+ err := models.DB.Create(category).Error
+ if err != nil {
+ log.Println("CategoryCreate Error:", err)
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "创建分类失败",
+ })
+ return
+ }
+ c.JSON(http.StatusOK, gin.H{
+ "code": 200,
+ "msg": "创建成功",
+ })
+}
+
+// GetCategoryModify
+// @Tags 管理员私有方法
+// @Summary 分类的修改
+// @Param authorization header string true "authorization"
+// @Param identity formData string true "identity"
+// @Param name formData string true "name"
+// @Param parentId formData int false "parentId"
+// @Success 200 {string} json "{"code":"200","data":""}"
+// @Router /admin/category_modify [put]
+func GetCategoryModify(c *gin.Context) {
+ identity := c.PostForm("identity")
+ name := c.PostForm("name")
+ parentId, _ := strconv.Atoi(c.PostForm("parentId"))
+ if name == "" || identity == "" {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "参数不正确",
+ })
+ return
+ }
+ category := &models.CategoryBasic{
+ Identity: identity,
+ Name: name,
+ ParentId: parentId,
+ }
+ err := models.DB.Model(new(models.CategoryBasic)).Where("identity = ?", identity).Updates(category).Error
+ if err != nil {
+ log.Println("CategoryModify Error:", err)
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "修改分类失败",
+ })
+ return
+ }
+ c.JSON(http.StatusOK, gin.H{
+ "code": 200,
+ "msg": "修改成功",
+ })
+}
+
+// GetCategoryDelete
+// @Tags 管理员私有方法
+// @Summary 分类的删除
+// @Param authorization header string true "authorization"
+// @Param identity query string true "identity"
+// @Success 200 {string} json "{"code":"200","data":""}"
+// @Router /admin/category_delete [delete]
+func GetCategoryDelete(c *gin.Context) {
+ identity := c.Query("identity")
+ if identity == "" {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "参数不正确",
+ })
+ return
+ }
+ var cnt int64
+ err := models.DB.Model(new(models.ProblemCategory)).Where("category_id = (SELECT id FROM category_basic WHERE identity = ? LIMIT 1)", identity).Count(&cnt).Error
+ if err != nil {
+ log.Println("Get ProblemCategory Error:", err)
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "获取分类关联的问题失败",
+ })
+ return
+ }
+ if cnt > 0 {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "该分类下面已存在问题,不可删除",
+ })
+ return
+ }
+ err = models.DB.Where("identity = ?", identity).Delete(new(models.CategoryBasic)).Error
+ if err != nil {
+ log.Println("Delete CategoryBasic Error:", err)
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "删除失败",
+ })
+ return
+ }
+ c.JSON(http.StatusOK, gin.H{
+ "code": 200,
+ "msg": "删除成功",
+ })
+}
diff --git a/service/problem.go b/service/problem.go
new file mode 100644
index 0000000..6a47364
--- /dev/null
+++ b/service/problem.go
@@ -0,0 +1,310 @@
+package service
+
+import (
+ "encoding/json"
+ "errors"
+ "github.com/gin-gonic/gin"
+ "gorm.io/gorm"
+ "log"
+ "lsq.com/define"
+ "lsq.com/helper"
+ "lsq.com/models"
+ "net/http"
+ "strconv"
+)
+
+// GetProblemList
+// @Tags 公共方法
+// @Summary 问题列表
+// @Param page query int false "第一页面"
+// @Param size query int false "size"
+// @Param keyword query string false "keyword"
+// @Param category_identity query string false "category_identity"
+// @Success 200 {string} json "{"code":"200","list":""}"
+// @Router /problem_list [get]
+func GetProblemList(c *gin.Context) {
+ //字符串转换为整数
+ size, _ := strconv.Atoi(c.DefaultQuery("size", define.DefaultSize))
+ page, err := strconv.Atoi(c.DefaultQuery("page", define.DefaultPage))
+ if err != nil {
+ log.Println("Get ProblemList Page strconv Error:", err)
+ return
+ }
+ //page == 1 ===> offset 0
+ page = (page - 1) * size
+ var count int64
+ keyword := c.Query("keyword")
+ categoryIdentity := c.Query("category_identity")
+
+ //创建一个切片存储models.Problem类型的元素
+ list := make([]*models.ProblemBasic, 0)
+ tx := models.GetProblemList(keyword, categoryIdentity)
+ //Offset起始位置;Limit每页的数据个数;Find查询的数据映射到struct
+ //Omit(): 查询结果中排除了xxx字段
+ err = tx.Count(&count).Omit("content").Offset(page).Limit(size).Find(&list).Error
+ if err != nil {
+ log.Println("Get Problem List Error:", err)
+ return
+ }
+
+ c.JSON(http.StatusOK, gin.H{
+ "code": 200,
+ "data": map[string]interface{}{
+ "list": list,
+ "count": count,
+ },
+ })
+}
+
+// GetProblemDetail
+// @Tags 公共方法
+// @Summary 问题详情
+// @Param identity query string false "problem_identity"
+// @Success 200 {string} json "{"code":"200","list":""}"
+// @Router /problem_detail [get]
+func GetProblemDetail(c *gin.Context) {
+ identity := c.Query("identity")
+ if identity == "" {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "问题唯一标识不能为空",
+ })
+ return
+ }
+ data := new(models.ProblemBasic)
+ err := models.DB.Where("identity = ?", identity).
+ Preload("ProblemCategories").
+ Preload("ProblemCategories.CategoryBasic").
+ First(&data).Error
+ if err != nil {
+ if err == gorm.ErrRecordNotFound {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "问题不存在",
+ })
+ return
+ }
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "Get ProblemDetail Error:" + err.Error(),
+ })
+ return
+ }
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "data": data,
+ })
+}
+
+// ProblemCreate
+// @Tags 管理员私有方法
+// @Summary 问题创建
+// @Param authorization header string true "authorization"
+// @Param title formData string true "title"
+// @Param content formData string true "content"
+// @Param max_runtime formData int false "max_runtime"
+// @Param max_mem formData int false "max_mem"
+// @Param category_ids formData array false "category_ids"
+// @Param test_cases formData array true "test_cases"
+// @Success 200 {string} json "{"code":"200","list":""}"
+// @Router /admin/problem_create [post]
+func ProblemCreate(c *gin.Context) {
+ title := c.PostForm("title")
+ content := c.PostForm("content")
+ maxRuntime, _ := strconv.Atoi(c.PostForm("max_runtime"))
+ maxMem, _ := strconv.Atoi(c.PostForm("max_mem"))
+ categoryIds := c.PostFormArray("category_ids")
+ testCases := c.PostFormArray("test_cases")
+ if title == "" || content == "" || len(testCases) == 0 {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "参数不能为空",
+ })
+ return
+ }
+ identity := helper.GetUUID()
+ data := &models.ProblemBasic{
+ Identity: identity,
+ Title: title,
+ Content: content,
+ MaxRuntime: maxRuntime,
+ MaxMem: maxMem,
+ }
+ //处理分类
+ categoryBasics := make([]*models.ProblemCategory, 0)
+ for _, id := range categoryIds {
+ categoryId, _ := strconv.Atoi(id)
+ categoryBasics = append(categoryBasics, &models.ProblemCategory{
+ ProblemId: data.ID,
+ CategoryId: uint(categoryId),
+ })
+ }
+ data.ProblemCategories = categoryBasics
+
+ //处理测试用例
+ testCaseBasics := make([]*models.TestCase, 0)
+ for _, testCase := range testCases {
+ caseMap := make(map[string]string)
+ err := json.Unmarshal([]byte(testCase), &caseMap)
+ if err != nil {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "测试用例格式错误1",
+ })
+ return
+ }
+ if _, ok := caseMap["input"]; !ok {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "测试用例格式错误2",
+ })
+ return
+ }
+ if _, ok := caseMap["output"]; !ok {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "测试用例格式错误3",
+ })
+ return
+ }
+ testCaseBasic := &models.TestCase{
+ Identity: helper.GetUUID(),
+ ProblemIdentity: identity,
+ Input: caseMap["input"],
+ Output: caseMap["Output"],
+ }
+ testCaseBasics = append(testCaseBasics, testCaseBasic)
+ }
+ data.TestCase = testCaseBasics
+
+ //创建问题
+ err := models.DB.Create(data).Error
+ if err != nil {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "Problem Create Error:" + err.Error(),
+ })
+ return
+ }
+ c.JSON(http.StatusOK, gin.H{
+ "code": 200,
+ "data": map[string]interface{}{
+ "identity": data.Identity,
+ },
+ })
+
+}
+
+// ProblemModify
+// @Tags 管理员私有方法
+// @Summary 问题修改
+// @Param authorization header string true "authorization"
+// @Param identity formData string true "identity"
+// @Param title formData string true "title"
+// @Param content formData string true "content"
+// @Param max_runtime formData int false "max_runtime"
+// @Param max_mem formData int false "max_mem"
+// @Param category_ids formData []string false "category_ids" collectionFormat(multi)
+// @Param test_cases formData []string true "test_cases" collectionFormat(multi)
+// @Success 200 {string} json "{"code":"200","list":""}"
+// @Router /admin/problem_modify [put]
+func ProblemModify(c *gin.Context) {
+ identity := c.PostForm("identity")
+ content := c.PostForm("content")
+ title := c.PostForm("title")
+ maxRuntime, _ := strconv.Atoi(c.PostForm("max_runtime"))
+ maxMem, _ := strconv.Atoi(c.PostForm("max_mem"))
+ categoryIds := c.PostFormArray("category_ids")
+ testCases := c.PostFormArray("test_cases")
+ if identity == "" || title == "" || content == "" || len(categoryIds) == 0 || len(testCases) == 0 || maxRuntime == 0 || maxMem == 0 {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "参数不能为空",
+ })
+ return
+ }
+ if err := models.DB.Transaction(func(tx *gorm.DB) error {
+ //问题基础信息保存 problemBasic
+ problemBasic := &models.ProblemBasic{
+ Identity: identity,
+ Title: title,
+ Content: content,
+ MaxRuntime: maxRuntime,
+ MaxMem: maxMem,
+ }
+ err := tx.Where("identity = ?", identity).Updates(problemBasic).Error
+ if err != nil {
+ return err
+ }
+ //查询问题详情
+ err = tx.Where("identity = ?", identity).Find(problemBasic).Error
+ if err != nil {
+ return err
+ }
+ //关联问题分类的更新
+ //1.删除已存在的关联关系
+ err = tx.Where("problem_id = ?", problemBasic.ID).Delete(new(models.ProblemCategory)).Error
+ if err != nil {
+ return err
+ }
+ //2.新增关联关系
+ pcs := make([]*models.ProblemCategory, 0)
+ for _, id := range categoryIds {
+ intId, _ := strconv.Atoi(id)
+ pcs = append(pcs, &models.ProblemCategory{
+ ProblemId: problemBasic.ID,
+ CategoryId: uint(intId),
+ })
+ }
+ err = tx.Create(&pcs).Error
+ if err != nil {
+ return err
+ }
+
+ //关联测试案例的更新
+ // 1、删除已存在的关联关系
+ err = tx.Where("problem_identity = ?", identity).Delete(new(models.TestCase)).Error
+ if err != nil {
+ return err
+ }
+ // 2、增加新的关联关系
+ tcs := make([]*models.TestCase, 0)
+ caseMap := make(map[string]string, 0)
+ for _, testCases := range testCases {
+ err := json.Unmarshal([]byte(testCases), &caseMap)
+ if err != nil {
+ return err
+ }
+ if _, ok := caseMap["input"]; !ok {
+ return errors.New("测试案例[input]格式错误")
+ }
+ if _, ok := caseMap["output"]; !ok {
+ return errors.New("测试案例[output]格式错误")
+ }
+ // 举个例子 {"input":"1 2\n","output":"3\n"}
+ tcs = append(tcs, &models.TestCase{
+ Identity: helper.GetUUID(),
+ ProblemIdentity: identity,
+ Input: caseMap["input"],
+ Output: caseMap["output"],
+ })
+ }
+ err = tx.Create(tcs).Error
+ if err != nil {
+ return err
+ }
+ return nil
+ }); err != nil {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "Problem Modify Error" + err.Error(),
+ })
+ return
+ }
+ c.JSON(http.StatusOK, gin.H{
+ "code": 200,
+ "msg": "问题修改成功",
+ })
+ return
+
+}
diff --git a/service/submit.go b/service/submit.go
new file mode 100644
index 0000000..1d7670f
--- /dev/null
+++ b/service/submit.go
@@ -0,0 +1,239 @@
+package service
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "github.com/gin-gonic/gin"
+ "gorm.io/gorm"
+ "io"
+ "io/ioutil"
+ "log"
+ "lsq.com/define"
+ "lsq.com/helper"
+ "lsq.com/models"
+ "net/http"
+ "os/exec"
+ "runtime"
+ "strconv"
+ "sync"
+ "time"
+)
+
+// GetSubmitList
+// @Tags 公共方法
+// @Summary 提交列表
+// @Param page query int false "第一页面"
+// @Param size query int false "size"
+// @Param problem_identity query string false "problem_identity"
+// @Param user_identity query string false "user_identity"
+// @Param status query int false "status"
+// @Success 200 {string} json "{"code":"200","list":""}"
+// @Router /submit_list [get]
+func GetSubmitList(c *gin.Context) {
+ //字符串转换为整数
+ size, _ := strconv.Atoi(c.DefaultQuery("size", define.DefaultSize))
+ page, err := strconv.Atoi(c.DefaultQuery("page", define.DefaultPage))
+ if err != nil {
+ log.Println("Get ProblemList Page strconv Error:", err)
+ return
+ }
+ //page == 1 ===> offset 0
+ page = (page - 1) * size
+
+ var count int64
+ list := make([]models.SubmitBasic, 0)
+
+ problemIdentity := c.Query("problem_identity")
+ userIdentity := c.Query("user_identity")
+ status, _ := strconv.Atoi(c.Query("status"))
+ tx := models.GetSubmitList(problemIdentity, userIdentity, status)
+ err = tx.Count(&count).Offset(page).Limit(size).Find(&list).Error
+ if err != nil {
+ log.Println("Get Problem List List Error:", err)
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "Get Submit List Error:" + err.Error(),
+ })
+ return
+ }
+ c.JSON(http.StatusOK, gin.H{
+ "code": 200,
+ "data": map[string]interface{}{
+ "list": list,
+ "count": count,
+ },
+ })
+}
+
+// Submit
+// @Tags 用户私有方法
+// @Summary 代码提交
+// @Param authorization header string true "authorization"
+// @Param problem_identity query string true "problem_identity"
+// @Param code body string true "code"
+// @Success 200 {string} json "{"code":"200","data":""}"
+// @Router /user/submit [post]
+func Submit(c *gin.Context) {
+ problemIdentity := c.Query("problem_identity")
+ code, err := ioutil.ReadAll(c.Request.Body)
+ if err != nil {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "Read Code Error:" + err.Error(),
+ })
+ return
+ }
+ // 代码保存
+ path, err := helper.CodeSave(code)
+ if err != nil {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "Code Save Error:" + err.Error(),
+ })
+ return
+ }
+ u, _ := c.Get("user_claims")
+ userClaim := u.(*helper.UserClaims)
+ sb := &models.SubmitBasic{
+ Identity: helper.GetUUID(),
+ ProblemIdentity: problemIdentity,
+ UserIdentity: userClaim.Identity,
+ Path: path,
+ }
+ // 代码判断
+ pb := new(models.ProblemBasic)
+ err = models.DB.Where("identity = ?", problemIdentity).Preload("TestCase").First(pb).Error
+ if err != nil {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "Get Problem Error:" + err.Error(),
+ })
+ return
+ }
+ // 答案错误的channel
+ WA := make(chan int)
+ // 超内存的channel
+ OOM := make(chan int)
+ // 编译错误的channel
+ CE := make(chan int)
+ // 答案正确的channel
+ AC := make(chan int)
+ // 非法代码的channel
+ EC := make(chan struct{})
+
+ // 通过的个数
+ passCount := 0
+ var lock sync.Mutex
+ // 提示信息
+ var msg string
+
+ for _, testCase := range pb.TestCase {
+ testCase := testCase
+ go func() {
+ cmd := exec.Command("go", "run", path)
+ var out, stderr bytes.Buffer
+ cmd.Stderr = &stderr
+ cmd.Stdout = &out
+ stdinPipe, err := cmd.StdinPipe()
+ if err != nil {
+ log.Fatalln(err)
+ }
+ io.WriteString(stdinPipe, testCase.Input) //todo +"\n"
+
+ var bm runtime.MemStats
+ runtime.ReadMemStats(&bm)
+ //根据测试的输入案例进行运行,拿到输出结果和标准输出结果进行比对
+ if err = cmd.Run(); err != nil {
+ log.Println(err, stderr.String())
+ if err.Error() == "exit status 2" {
+ msg = stderr.String()
+ CE <- 1
+ return
+ }
+ }
+ var em runtime.MemStats
+ runtime.ReadMemStats(&em)
+ //答案错误
+ fmt.Println("===testCase=" + testCase.Output + "==testCase==")
+ fmt.Println("==out==" + out.String() + "==out==")
+ if testCase.Output != out.String() {
+ msg = "答案错误"
+ WA <- 1
+ return
+ }
+ //运行超内存
+ if em.Alloc/1024-(bm.Alloc/1024) > uint64(pb.MaxMem) {
+ msg = "运行超内存"
+ OOM <- 1
+ return
+ }
+ lock.Lock()
+ passCount++
+ if passCount == len(pb.TestCase) {
+ AC <- 1
+ }
+ lock.Unlock()
+ }()
+ }
+ select {
+ case <-EC:
+ msg = "无效代码"
+ sb.Status = 6
+ case <-WA:
+ msg = "答案错误"
+ sb.Status = 2
+ case <-OOM:
+ msg = "运行超内存"
+ sb.Status = 4
+ case <-CE:
+ sb.Status = 5
+ case <-AC:
+ msg = "答案正确"
+ sb.Status = 1
+ case <-time.After(time.Millisecond * time.Duration(pb.MaxRuntime)):
+ if passCount == len(pb.TestCase) {
+ sb.Status = 1
+ msg = "答案正确"
+ } else {
+ sb.Status = 3
+ msg = "运行超时"
+ }
+ }
+
+ if err = models.DB.Transaction(func(tx *gorm.DB) error {
+ err = models.DB.Create(sb).Error
+ if err != nil {
+ return errors.New("SubmitBasic Save Error:" + err.Error())
+ }
+ m := make(map[string]interface{})
+ m["submit_num"] = gorm.Expr("submit_num + ?", 1)
+ if sb.Status == 1 {
+ m["pass_num"] = gorm.Expr("pass_num + ?", 1)
+ }
+ //更新user_basic
+ err = tx.Model(new(models.UserBasic)).Where("identity = ?", userClaim.Identity).Updates(m).Error
+ if err != nil {
+ return errors.New("UserBasic Modify Error:" + err.Error())
+ }
+ //更新problem_basic
+ err = tx.Model(new(models.ProblemBasic)).Where("identity = ?", problemIdentity).Updates(m).Error
+ if err != nil {
+ return errors.New("ProblemBasic Modify Error:" + err.Error())
+ }
+ return nil
+ }); err != nil {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "Submit Error:" + err.Error(),
+ })
+ return
+ }
+ c.JSON(http.StatusOK, gin.H{
+ "code": 200,
+ "data": map[string]interface{}{
+ "status": sb.Status,
+ "msg": msg,
+ },
+ })
+}
diff --git a/service/user.go b/service/user.go
new file mode 100644
index 0000000..cc3a90a
--- /dev/null
+++ b/service/user.go
@@ -0,0 +1,255 @@
+package service
+
+import (
+ "github.com/gin-gonic/gin"
+ "gorm.io/gorm"
+ "log"
+ "lsq.com/define"
+ "lsq.com/helper"
+ "lsq.com/models"
+ "net/http"
+ "strconv"
+ "time"
+)
+
+// GetUserDetailAll
+// @Tags 公共方法
+// @Summary 用户详情
+// @Param identity query string false "problem_identity"
+// @Success 200 {string} json "{"code":"200","list":""}"
+// @Router /user_detail [get]
+func GetUserDetailAll(c *gin.Context) {
+ identity := c.Query("identity")
+ if identity == "" {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "用户唯一标识不能为空",
+ })
+ return
+ }
+ data := new(models.UserBasic)
+ err := models.DB.Omit("password").Where("identity = ?", identity).Find(&data).Error
+ if err != nil {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "Get User Detail Identity:" + identity + "Error" + err.Error(),
+ })
+ return
+ }
+ c.JSON(http.StatusOK, gin.H{
+ "code": 200,
+ "data": data,
+ })
+}
+
+// Login
+// @Tags 公共方法
+// @Summary 用户登录
+// @Param username formData string false "username"
+// @Param password formData string false "password"
+// @Success 200 {string} json "{"code":"200","list":""}"
+// @Router /login [post]
+func Login(c *gin.Context) {
+ username := c.PostForm("username")
+ password := c.PostForm("password")
+ if username == "" || password == "" {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "必填信息为空",
+ })
+ }
+ //md5
+ password = helper.GetMd5(password)
+ data := new(models.UserBasic)
+ err := models.DB.Where("name=? AND password = ?", username, password).Find(&data).Error
+ if err != nil {
+ if err == gorm.ErrRecordNotFound {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "用户名或密码错误",
+ })
+ return
+ }
+ c.JSON(http.StatusOK, gin.H{
+ "code": 200,
+ "msg": "Get UserBasic Error:" + err.Error(),
+ })
+ return
+ }
+
+ token, err := helper.GenerateToken(data.Identity, data.Name, data.IsAdmin)
+ if err != nil {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "GenerateToken Error:" + err.Error(),
+ })
+ }
+
+ c.JSON(http.StatusOK, gin.H{
+ "code": 200,
+ "data": map[string]interface{}{
+ "token": token,
+ },
+ })
+
+}
+
+// SendCode
+// @Tags 公共方法
+// @Summary 发送验证码
+// @Param email formData string false "email"
+// @Success 200 {string} json "{"code":"200","list":""}"
+// @Router /send_code [post]
+func SendCode(c *gin.Context) {
+ email := c.PostForm("email")
+ if email == "" {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "参数不正确",
+ })
+ return
+ }
+ //TODO
+ code := helper.GetRand()
+ models.RDB.Set(c, email, code, time.Second*300)
+ err := helper.SendCode(email, code)
+ if err != nil {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "Send Code Error:" + err.Error(),
+ })
+ return
+ }
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "验证码发送成功",
+ })
+}
+
+// Register
+// @Tags 公共方法
+// @Summary 用户注册
+// @Param mail formData string true "mail"
+// @Param code formData string true "code"
+// @Param name formData string true "name"
+// @Param password formData string true "password"
+// @Param phone formData string false "phone"
+// @Success 200 {string} json "{"code":"200","list":""}"
+// @Router /register [post]
+func Register(c *gin.Context) {
+ mail := c.PostForm("mail")
+ userCode := c.PostForm("code")
+ name := c.PostForm("name")
+ password := c.PostForm("password")
+ phone := c.PostForm("phone")
+ if mail == "" || userCode == "" || name == "" || password == "" {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "参数不正确",
+ })
+ return
+ }
+ //验证码是否正确
+ sysCode, err := models.RDB.Get(c, mail).Result()
+ if err != nil {
+ log.Printf("Get Code Error:%v", err)
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "验证码错误,请重新获取验证码",
+ })
+ return
+ }
+ if sysCode != userCode {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "验证码不正确",
+ })
+ return
+ }
+ //判断邮箱是否已存在
+ var cnt int64
+ err = models.DB.Where("mail = ?", mail).Model(new(models.UserBasic)).Count(&cnt).Error
+ if err != nil {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "Get User Error" + err.Error(),
+ })
+ return
+ }
+ if cnt > 0 {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "该邮箱已被注册",
+ })
+ return
+ }
+
+ //数据插入
+ userIdentity := helper.GetUUID()
+ data := &models.UserBasic{
+ Identity: userIdentity,
+ Name: name,
+ Password: helper.GetMd5(password),
+ Phone: phone,
+ Mail: mail,
+ }
+ err = models.DB.Create(data).Error
+ if err != nil {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "Get User Error:" + err.Error(),
+ })
+ return
+ }
+ //生成token
+ token, err := helper.GenerateToken(userIdentity, name, data.IsAdmin)
+ if err != nil {
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "msg": "Generate Token Error:" + err.Error(),
+ })
+ return
+ }
+ c.JSON(http.StatusOK, gin.H{
+ "code": -1,
+ "data": map[string]interface{}{
+ "token": token,
+ },
+ })
+}
+
+// GetRankList
+// @Tags 公共方法
+// @Summary 用户排行榜
+// @Param page query string false "page"
+// @Param size query string false "size"
+// @Success 200 {string} json "{"code":"200","list":""}"
+// @Router /rank_list [get]
+func GetRankList(c *gin.Context) {
+ size, _ := strconv.Atoi(c.DefaultQuery("size", define.DefaultSize))
+ page, err := strconv.Atoi(c.DefaultQuery("page", define.DefaultPage))
+ if err != nil {
+ log.Println("Get ProblemList Page strconv Error:", err)
+ return
+ }
+ //page == 1 ===> offset 0
+ page = (page - 1) * size
+ var count int64
+ list := make([]*models.UserBasic, 0)
+ err = models.DB.Model(new(models.UserBasic)).Count(&count).Order("finish_problem_num DESC,submit_num ASC").
+ Offset(page).Limit(size).Find(&list).Error
+ if err != nil {
+ c.JSON(http.StatusOK, gin.H{
+ "code": 200,
+ "msg": "Get Rank List Error:" + err.Error(),
+ })
+ }
+
+ c.JSON(http.StatusOK, gin.H{
+ "code": 200,
+ "data": map[string]interface{}{
+ "list": list,
+ "count": count,
+ },
+ })
+}
diff --git a/test/email_test.go b/test/email_test.go
new file mode 100644
index 0000000..8f40667
--- /dev/null
+++ b/test/email_test.go
@@ -0,0 +1,26 @@
+package test
+
+import (
+ "github.com/jordan-wright/email"
+ "net/smtp"
+ "testing"
+)
+
+func TestSendEmail(t *testing.T) {
+ e := email.NewEmail()
+ e.From = "Crayon <2993373191@qq.com>"
+ e.To = []string{"sudolsq@gmail.com"}
+ e.Subject = "验证发送测试"
+
+ e.HTML = []byte("Fancy HTML12311231 is supported, too!
")
+ err := e.Send("smtp.qq.com:587", smtp.PlainAuth("", "2993373191@qq.com", "vlkrwkqjayqedehc", "smtp.qq.com"))
+ //返回EOF时,关闭SLL重试
+ //err := e.SendWithTLS("smtp.qq.com:587",
+ // smtp.PlainAuth("", "2993373191@qq.com",
+ // "vlkrwkqjayqedehc", "smtp.qq.com"),
+ // &tls.Config{InsecureSkipVerify: true, ServerName: "smtp.qq.com"})
+
+ if err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/test/gorm_test.go b/test/gorm_test.go
new file mode 100644
index 0000000..845fba0
--- /dev/null
+++ b/test/gorm_test.go
@@ -0,0 +1,25 @@
+package test
+
+import (
+ "fmt"
+ "gorm.io/driver/mysql"
+ "gorm.io/gorm"
+ "lsq.com/models"
+ "testing"
+)
+
+func TestGormTest(t *testing.T) {
+ dsn := "root:root@tcp(127.0.0.1:3306)/gin_gorm_oj?charset=utf8mb4&parseTime=True&loc=Local"
+ db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
+ if err != nil {
+ t.Fatal(err)
+ }
+ data := make([]*models.ProblemBasic, 0)
+ err = db.Find(&data).Error
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, v := range data {
+ fmt.Printf("Problem====>%v\n", v)
+ }
+}
diff --git a/test/jwt_test.go b/test/jwt_test.go
new file mode 100644
index 0000000..2d0bd28
--- /dev/null
+++ b/test/jwt_test.go
@@ -0,0 +1,54 @@
+package test
+
+import (
+ "fmt"
+ "github.com/golang-jwt/jwt/v4"
+ "testing"
+ "time"
+)
+
+type UserClaims struct {
+ Identity string `json:"identity"`
+ Name string `json:"name"`
+ jwt.StandardClaims
+}
+
+// TODO 签名密钥
+var myKey = []byte("gin-gorm-oj-key")
+
+func TestGenerateToken(t *testing.T) {
+ UserClaims := &UserClaims{
+ Identity: "user_1",
+ Name: "get",
+ StandardClaims: jwt.StandardClaims{
+ NotBefore: time.Now().Unix() - 60, // 令牌在当前时间的前60秒之前不生效
+ ExpiresAt: time.Now().Unix() + 5, // 令牌将在当前时间的后5秒过期
+ Issuer: "lsq", // 令牌的发行者
+ },
+ }
+ //TODO 使用指定的签名方法和声明创建一个新的令牌
+ token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaims)
+ //TODO 使用签名密钥对令牌进行签名,并获取完整的签名后的令牌字符串
+ tokenString, err := token.SignedString(myKey)
+ if err != nil {
+ t.Fatal(err)
+ return
+ }
+ fmt.Println(tokenString)
+ //eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6InVzZXJfMSIsIm5hbWUiOiJnZXQifQ.taKAmMZu6-6ioE4hSKqUgn9lHrqXSw-2TyEQTeNOreA
+}
+
+func TestAnalyseToken(t *testing.T) {
+ tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6InVzZXJfMSIsIm5hbWUiOiJnZXQifQ.taKAmMZu6-6ioE4hSKqUgn9lHrqXSw-2TyEQTeNOreA"
+ userClaim := new(UserClaims)
+ //TODO 解析 JWT,并在解析的过程中验证签名
+ claims, err := jwt.ParseWithClaims(tokenString, userClaim, func(token *jwt.Token) (interface{}, error) {
+ return myKey, nil
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if claims.Valid {
+ fmt.Println(userClaim)
+ }
+}
diff --git a/test/redis_test.go b/test/redis_test.go
new file mode 100644
index 0000000..97f6abd
--- /dev/null
+++ b/test/redis_test.go
@@ -0,0 +1,37 @@
+package test
+
+import (
+ "context"
+ "fmt"
+ "github.com/redis/go-redis/v9"
+ "lsq.com/models"
+ "testing"
+ "time"
+)
+
+var ctx = context.Background()
+var rdb = redis.NewClient(&redis.Options{
+ Addr: "127.0.0.1:6379",
+ Password: "", // no password set
+ DB: 0, // use default DB
+})
+
+func TestRedisSet(t *testing.T) {
+ rdb.Set(ctx, "name", "mmc", time.Second*10)
+}
+
+func TestRedisGet(t *testing.T) {
+ v, err := rdb.Get(ctx, "name").Result()
+ if err != nil {
+ t.Fatal(err)
+ }
+ fmt.Println(v)
+}
+
+func TestRedisGetByModels(t *testing.T) {
+ v, err := models.RDB.Get(ctx, "name").Result()
+ if err != nil {
+ t.Fatal(err)
+ }
+ fmt.Println(v)
+}
diff --git a/test/uuid_test.go b/test/uuid_test.go
new file mode 100644
index 0000000..32ec28a
--- /dev/null
+++ b/test/uuid_test.go
@@ -0,0 +1,16 @@
+package test
+
+import (
+ uuid "github.com/satori/go.uuid"
+ "testing"
+)
+
+func TestGenerateUUID(t *testing.T) {
+ println(uuid.NewV4().String())
+ println(uuid.NewV4().String())
+ println(uuid.NewV4().String())
+ println(uuid.NewV4().String())
+ println(uuid.NewV4().String())
+ println(len(uuid.NewV4().String()))
+
+}