完成管理后台登录、登出操作
This commit is contained in:
parent
e2d2891ebb
commit
4e9f58a0e7
|
@ -12,4 +12,13 @@ See the Mulan PSL v2 for more details. */
|
||||||
|
|
||||||
#admin-right-content {
|
#admin-right-content {
|
||||||
padding-left: 200px;
|
padding-left: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#login-grid {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#login-grid>.column {
|
||||||
|
max-width: 500px;
|
||||||
}
|
}
|
|
@ -8,6 +8,51 @@
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
$('#login-form')
|
||||||
|
.form({
|
||||||
|
fields: {
|
||||||
|
account: {
|
||||||
|
identifier : 'account',
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
type : 'empty',
|
||||||
|
prompt : '账户名不能为空'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type : 'length[5]',
|
||||||
|
prompt : '账户名长度不得少于5位'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
identifier : 'password',
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
type : 'empty',
|
||||||
|
prompt : '密码不能为空'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type : 'length[8]',
|
||||||
|
prompt : '密码长度不得少于8位'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
captcha: {
|
||||||
|
identifier : 'captcha-text',
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
type : 'empty',
|
||||||
|
prompt : '验证码不能为空'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type : 'length[6]',
|
||||||
|
prompt : '验证码长度不得少于6位'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$('.message .close')
|
$('.message .close')
|
||||||
.on('click', function() {
|
.on('click', function() {
|
||||||
$(this)
|
$(this)
|
||||||
|
@ -378,4 +423,36 @@ function startToGrabRepos() {
|
||||||
});
|
});
|
||||||
}//end of if
|
}//end of if
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function reload_captcha() {
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: '/captcha',
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(r) {
|
||||||
|
$('#captcha-image').html('<img src="/captcha/'+r.result+'.png" />');
|
||||||
|
$('<input>').attr({type: 'hidden', value:r.result ,name: 'captcha-id'}).appendTo('#login-form');
|
||||||
|
},
|
||||||
|
error: function(e) {
|
||||||
|
errorToast($.parseJSON(e.responseText).message)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function sign_out() {
|
||||||
|
$('body').modal('confirm','温馨提示','确认退出 RepoStats 管理后端吗?', function(choice){
|
||||||
|
if (choice) {
|
||||||
|
$.ajax({
|
||||||
|
type:"POST",
|
||||||
|
url: "/admin/logout",
|
||||||
|
success: function() {
|
||||||
|
successToast('操作成功,再见!')
|
||||||
|
},
|
||||||
|
error: function(e) {
|
||||||
|
errorToast($.parseJSON(e.responseText).message)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
|
@ -9,15 +9,54 @@
|
||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"net/http"
|
||||||
|
"repostats/storage"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AdminAuthHanlder() gin.HandlerFunc {
|
func AdminAuthHandler() gin.HandlerFunc {
|
||||||
return func(ctx *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
//TODO: auth handler
|
user, err := c.Cookie("RepoStatsAdmin")
|
||||||
log.Println("debug only--->" + ctx.Request.URL.Path)
|
if err != nil {
|
||||||
ctx.Next()
|
c.Redirect(http.StatusFound, "/login")
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cookie, err := c.Cookie("RepoStatsCookie")
|
||||||
|
if err != nil {
|
||||||
|
c.Redirect(http.StatusFound, "/login")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(user) <= 0 || len(cookie) <= 0 {
|
||||||
|
c.Redirect(http.StatusFound, "/login")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
found, err := storage.FindAdminByAccount(user)
|
||||||
|
if err != nil {
|
||||||
|
c.Redirect(http.StatusFound, "/login")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if found.IsEmpty() {
|
||||||
|
c.Redirect(http.StatusFound, "/login")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cValue, err := AdminCookieValue(found)
|
||||||
|
if err != nil {
|
||||||
|
c.Redirect(http.StatusFound, "/login")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.EqualFold(cValue, cookie) {
|
||||||
|
c.Redirect(http.StatusFound, "/login")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Next()
|
||||||
|
} //end of func
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,25 +8,121 @@
|
||||||
|
|
||||||
package controller
|
package controller
|
||||||
|
|
||||||
import "github.com/gin-gonic/gin"
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"repostats/model"
|
||||||
|
"repostats/storage"
|
||||||
|
"repostats/utils"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/dchest/captcha"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
// Login page controller
|
// Login page controller
|
||||||
//
|
//
|
||||||
// Display login page html
|
// Display login page html
|
||||||
func Login(ctx *gin.Context) {
|
func Login(ctx *gin.Context) {
|
||||||
|
ctx.HTML(http.StatusOK, "login.html", gin.H{
|
||||||
|
"title": "登录 - RepoStats",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Login action
|
// Login action
|
||||||
//
|
//
|
||||||
// Ask for account and password to DO the login action
|
// Ask for account and password to DO the login action
|
||||||
func DoLogin(ctx *gin.Context) {
|
func DoLogin(ctx *gin.Context) {
|
||||||
|
account := ctx.PostForm("account")
|
||||||
|
password := ctx.PostForm("password")
|
||||||
|
captchaText := ctx.PostForm("captcha-text")
|
||||||
|
captchaId := ctx.PostForm("captcha-id")
|
||||||
|
|
||||||
|
if utils.EmptyString(account) || utils.EmptyString(password) || len(account) < 5 || len(password) < 8 {
|
||||||
|
ctx.HTML(http.StatusOK, "login.html", gin.H{
|
||||||
|
"title": "错误 - RepoStats",
|
||||||
|
"error": "用户名或密码格式错误!",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if utils.EmptyString(captchaText) || utils.EmptyString(captchaId) || len(captchaText) < 6 {
|
||||||
|
ctx.HTML(http.StatusOK, "login.html", gin.H{
|
||||||
|
"title": "错误 - RepoStats",
|
||||||
|
"error": "验证码格式错误!",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//验证码有效性验证
|
||||||
|
if !captcha.VerifyString(captchaId, captchaText) {
|
||||||
|
ctx.HTML(http.StatusOK, "login.html", gin.H{
|
||||||
|
"title": "错误 - RepoStats",
|
||||||
|
"error": "验证码错误,请刷新页面再重新尝试!",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//用户名密码有效性验证
|
||||||
|
loginUser, err := storage.FindAdminByAccount(account)
|
||||||
|
if err != nil || loginUser.IsEmpty() {
|
||||||
|
ctx.HTML(http.StatusOK, "login.html", gin.H{
|
||||||
|
"title": "错误 - RepoStats",
|
||||||
|
"error": "用户名或密码错误",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pwd, _ := storage.PasswordBase58Hash(password)
|
||||||
|
if !strings.EqualFold(loginUser.Password, pwd) {
|
||||||
|
ctx.HTML(http.StatusOK, "login.html", gin.H{
|
||||||
|
"title": "错误 - RepoStats",
|
||||||
|
"error": "用户名或密码错误",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//Write Cookie to browser
|
||||||
|
cValue, err := AdminCookieValue(loginUser)
|
||||||
|
if err != nil {
|
||||||
|
ctx.HTML(http.StatusOK, "login.html", gin.H{
|
||||||
|
"title": "错误 - RepoStats",
|
||||||
|
"error": "内部错误,请联系管理员",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SetCookie("RepoStatsAdmin", loginUser.Account, 3600, "/", "", false, true)
|
||||||
|
ctx.SetCookie("RepoStatsCookie", cValue, 3600, "/", "", false, true)
|
||||||
|
ctx.Redirect(http.StatusFound, "/admin/gitee")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logout action
|
// Logout action
|
||||||
//
|
//
|
||||||
// Clean cookies and redirect to login page
|
// Clean cookies and redirect to login page
|
||||||
func DoLogout(ctx *gin.Context) {
|
func DoLogout(ctx *gin.Context) {
|
||||||
|
ctx.SetCookie("RepoStatsAdmin", "", -1, "/", "", false, true)
|
||||||
|
ctx.SetCookie("RepoStatsCookie", "", -1, "/", "", false, true)
|
||||||
|
ctx.Redirect(http.StatusFound, "/login")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ServeCaptchaImage(c *gin.Context) {
|
||||||
|
captcha.Server(200, 45).ServeHTTP(c.Writer, c.Request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RequestCaptchaImage(c *gin.Context) {
|
||||||
|
imageId := captcha.New()
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"result": imageId,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func AdminCookieValue(user model.Admin) (string, error) {
|
||||||
|
var result string
|
||||||
|
data, err := utils.Sha256Of(user.Account + "a=" + user.Password + "=e" + strconv.Itoa(user.ID))
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
return utils.Base58Encode(data), nil
|
||||||
}
|
}
|
||||||
|
|
8
go.mod
8
go.mod
|
@ -5,7 +5,9 @@ go 1.16
|
||||||
require (
|
require (
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
github.com/Masterminds/semver v1.5.0 // indirect
|
github.com/Masterminds/semver v1.5.0 // indirect
|
||||||
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
github.com/Masterminds/sprig v2.22.0+incompatible
|
||||||
|
github.com/btcsuite/btcutil v1.0.2
|
||||||
|
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
||||||
github.com/gin-gonic/gin v1.7.7
|
github.com/gin-gonic/gin v1.7.7
|
||||||
github.com/go-resty/resty/v2 v2.7.0
|
github.com/go-resty/resty/v2 v2.7.0
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
|
@ -14,7 +16,7 @@ require (
|
||||||
github.com/jmoiron/sqlx v1.3.4
|
github.com/jmoiron/sqlx v1.3.4
|
||||||
github.com/lib/pq v1.10.5
|
github.com/lib/pq v1.10.5
|
||||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||||
github.com/remeh/sizedwaitgroup v1.0.0 // indirect
|
github.com/remeh/sizedwaitgroup v1.0.0
|
||||||
gopkg.in/guregu/null.v4 v4.0.0 // indirect
|
gopkg.in/guregu/null.v4 v4.0.0
|
||||||
gopkg.in/ini.v1 v1.66.4
|
gopkg.in/ini.v1 v1.66.4
|
||||||
)
|
)
|
||||||
|
|
31
go.sum
31
go.sum
|
@ -4,8 +4,23 @@ github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3Q
|
||||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||||
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
|
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
|
||||||
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
||||||
|
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||||
|
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||||
|
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||||
|
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||||
|
github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts=
|
||||||
|
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=
|
||||||
|
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
|
||||||
|
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
|
||||||
|
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
|
||||||
|
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
|
||||||
|
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
||||||
|
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f h1:q/DpyjJjZs94bziQ7YkBmIlpqbVP7yw179rnzoNVX1M=
|
||||||
|
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f/go.mod h1:QGrK8vMWWHQYQ3QU9bw9Y9OPNfxccGzfb41qjvVeXtY=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
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-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
|
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
|
||||||
|
@ -21,21 +36,26 @@ github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPr
|
||||||
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
|
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
|
||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
|
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
|
||||||
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
|
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w=
|
github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w=
|
||||||
github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
|
github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
|
||||||
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
||||||
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
||||||
|
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
|
@ -52,6 +72,9 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OH
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E=
|
github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E=
|
||||||
github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo=
|
github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo=
|
||||||
|
@ -62,12 +85,17 @@ github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
|
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20211029224645-99673261e6eb h1:pirldcYWx7rx7kE5r+9WsOXPXK0+WH5+uZ7uPmJ44uM=
|
golang.org/x/net v0.0.0-20211029224645-99673261e6eb h1:pirldcYWx7rx7kE5r+9WsOXPXK0+WH5+uZ7uPmJ44uM=
|
||||||
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
||||||
|
@ -81,10 +109,13 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg=
|
gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg=
|
||||||
gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI=
|
gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI=
|
||||||
gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
|
gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
|
||||||
gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
type Admin struct {
|
||||||
|
ID int `db:"id"`
|
||||||
|
Account string `db:"account"`
|
||||||
|
Password string `db:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user Admin) IsEmpty() bool {
|
||||||
|
return reflect.DeepEqual(user, Admin{})
|
||||||
|
}
|
|
@ -71,10 +71,12 @@ func initRouter(router *gin.Engine) {
|
||||||
|
|
||||||
router.GET("/login", controller.Login)
|
router.GET("/login", controller.Login)
|
||||||
router.POST("/login", controller.DoLogin)
|
router.POST("/login", controller.DoLogin)
|
||||||
|
router.GET("/captcha/:imageId", controller.ServeCaptchaImage)
|
||||||
|
router.POST("/captcha", controller.RequestCaptchaImage)
|
||||||
|
|
||||||
admin := router.Group("/admin", controller.AdminAuthHanlder())
|
admin := router.Group("/admin", controller.AdminAuthHandler())
|
||||||
admin.POST("/logout", controller.DoLogout)
|
admin.POST("/logout", controller.DoLogout)
|
||||||
admin.GET("/", func(ctx *gin.Context) { ctx.Redirect(http.StatusFound, "/admin/dashboard") })
|
admin.GET("/", func(ctx *gin.Context) { ctx.Redirect(http.StatusFound, "/admin/gitee") })
|
||||||
admin.GET("/gitee", controller.GiteePage)
|
admin.GET("/gitee", controller.GiteePage)
|
||||||
|
|
||||||
admin.GET("/repos", controller.ReposPage)
|
admin.GET("/repos", controller.ReposPage)
|
||||||
|
|
|
@ -88,7 +88,7 @@ func GrabRepo(wg *sizedwaitgroup.SizedWaitGroup, repo gitee_model.Repository,
|
||||||
str := strings.Split(repo.FullName, "/")
|
str := strings.Split(repo.FullName, "/")
|
||||||
repoInfo, err := network.GetGiteeRepo(str[0], str[1])
|
repoInfo, err := network.GetGiteeRepo(str[0], str[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[RepoStats] failed during GetGiteeRepo %s", repo.HTMLURL)
|
log.Printf("[RepoStats] failed during GetGiteeRepo %s, %s", repo.HTMLURL, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
-- Database Structure For RepoStats
|
-- Database Structure For RepoStats
|
||||||
CREATE DATABASE repostats ENCODING 'UTF8';
|
CREATE DATABASE repostats ENCODING 'UTF8';
|
||||||
|
|
||||||
|
CREATE TABLE public.users (
|
||||||
|
id serial4 NOT NULL,
|
||||||
|
account varchar(200) NOT NULL,
|
||||||
|
password text NOT NULL,
|
||||||
|
CONSTRAINT users_pk PRIMARY KEY (id),
|
||||||
|
CONSTRAINT users_account_un UNIQUE (account)
|
||||||
|
);
|
|
@ -0,0 +1,35 @@
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"repostats/model"
|
||||||
|
"repostats/utils"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewAdmin(account string, password string) error {
|
||||||
|
query := `INSERT INTO public.users (account, "password") VALUES(:account,:password)`
|
||||||
|
data, err := PasswordBase58Hash(password)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return DbNamedExec(query, model.Admin{Account: account, Password: data})
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateAdmin(user model.Admin) error {
|
||||||
|
query := `UPDATE public.users SET account = :account , "password" = :password WHERE id = :id`
|
||||||
|
return DbNamedExec(query, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindAdminByAccount(account string) (model.Admin, error) {
|
||||||
|
var user model.Admin
|
||||||
|
query := `SELECT * FROM public.users u WHERE lower(u.account) = $1`
|
||||||
|
return user, DbGet(query, &user, strings.ToLower(account))
|
||||||
|
}
|
||||||
|
|
||||||
|
func PasswordBase58Hash(password string) (string, error) {
|
||||||
|
data, err := utils.Sha256Of(password)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return utils.Base58Encode(data), nil
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"repostats/utils"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewAdmin(t *testing.T) {
|
||||||
|
|
||||||
|
testSetup(t)
|
||||||
|
defer testTeardown(t)
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
account string
|
||||||
|
password string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{name: "TestCase1", args: args{account: "repostats", password: "-2aDzm=0(ln_9^1"}, wantErr: false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if err := NewAdmin(tt.args.account, tt.args.password); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("NewAdmin() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSetup(t *testing.T) {
|
||||||
|
_, err := utils.InitConfig("../repostats.ini")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
utils.ExitOnError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = InitDatabaseService()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
utils.ExitOnError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testTeardown(t *testing.T) {
|
||||||
|
DbClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFindAdminByAccount(t *testing.T) {
|
||||||
|
|
||||||
|
testSetup(t)
|
||||||
|
defer testTeardown(t)
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
account string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{name: "TestCase 2", args: args{account: "repostats"}, want: "EZ2zQjC3fqbkvtggy9p2YaJiLwx1kKPTJxvqVzowtx6t", wantErr: false},
|
||||||
|
// {name: "TestCase 2", args: args{account: "repostats1"}, want: "ss", wantErr: false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := FindAdminByAccount(tt.args.account)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("FindAdminByAccount() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got.Password, tt.want) {
|
||||||
|
t.Errorf("FindAdminByAccount() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
{{define "login.html" -}}
|
||||||
|
{{- template "header.html" .}}
|
||||||
|
<div class="ui inverted borderless large menu">
|
||||||
|
<div class="ui container">
|
||||||
|
<a class="ui inverted header item" target="_self" href="https://gitee.com/barat/repostats">
|
||||||
|
<div class="content">RepoStats</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="login-grid" class="ui middle aligned center aligned grid">
|
||||||
|
<div class="column">
|
||||||
|
<h2 class="ui image header">
|
||||||
|
<div class="content">
|
||||||
|
RepoStats
|
||||||
|
</div>
|
||||||
|
</h2>
|
||||||
|
<form id="login-form" class="ui large form" action="/login" method="POST">
|
||||||
|
<div class="ui stacked segment">
|
||||||
|
<div class="field">
|
||||||
|
<div class="ui left icon input">
|
||||||
|
<i class="user icon"></i>
|
||||||
|
<input type="text" name="account" placeholder="Account">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div class="ui left icon input">
|
||||||
|
<i class="lock icon"></i>
|
||||||
|
<input type="password" name="password" placeholder="Password">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div class="two fields">
|
||||||
|
<div class="field">
|
||||||
|
<div class="ui left icon input">
|
||||||
|
<i class="image icon"></i>
|
||||||
|
<input type="text" name="captcha-text" placeholder="验证码">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="captcha-image" class="field"><a class="ui input" href="javascript:reload_captcha()">点击获取验证码</a></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui fluid large black submit button">Login</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui error message"></div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{- template "footer.html" .}}
|
||||||
|
{{end -}}
|
|
@ -12,6 +12,6 @@
|
||||||
<a class="{{if eq .current_url "/admin/prs"}}active {{end}}item" target="_self" href="/admin/prs">Pull Request 列表</a>
|
<a class="{{if eq .current_url "/admin/prs"}}active {{end}}item" target="_self" href="/admin/prs">Pull Request 列表</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a class="item" target="_self" href="javascript:sign_out_config()">安全退出</a>
|
<a class="item" target="_self" href="javascript:sign_out()">安全退出</a>
|
||||||
</div><!--end of left-menu-->
|
</div><!--end of left-menu-->
|
||||||
{{end -}}
|
{{end -}}
|
|
@ -9,6 +9,7 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -18,12 +19,13 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcutil/base58"
|
||||||
"github.com/remeh/sizedwaitgroup"
|
"github.com/remeh/sizedwaitgroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MAX_ROUTINE_NUMBER = 25
|
MAX_ROUTINE_NUMBER = 20
|
||||||
GITEE_SCHEDULER_INTERVAL = 4 * time.Hour
|
GITEE_SCHEDULER_INTERVAL = 6 * time.Hour
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -99,3 +101,16 @@ func ParseGiteeRepoUrl(urlStr string) (string, string, error) {
|
||||||
return "", "", errors.New("无法解析该链接")
|
return "", "", errors.New("无法解析该链接")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Sha256Of(input string) ([]byte, error) {
|
||||||
|
algorithm := sha256.New()
|
||||||
|
_, err := algorithm.Write([]byte(strings.TrimSpace(input)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return algorithm.Sum(nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Base58Encode(data []byte) string {
|
||||||
|
return base58.Encode(data)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue