增加登录日志

pull/21/merge
ouqiang 2017-05-01 06:02:49 +08:00
parent a7977894d6
commit 98c1a1c3f9
16 changed files with 182 additions and 71 deletions

36
models/login_log.go Normal file
View File

@ -0,0 +1,36 @@
package models
import (
"time"
)
// 用户登录日志
type LoginLog struct {
Id int `xorm:"pk autoincr notnull "`
Username string `xorm:"varchar(32) notnull"`
Ip string `xorm:"varchar(15) not null"`
Created time.Time `xorm:"datetime notnull created"`
BaseModel `xorm:"-"`
}
func (log *LoginLog) Create() (insertId int, err error) {
_, err = Db.Insert(log)
if err == nil {
insertId = log.Id
}
return
}
func (log *LoginLog) List(params CommonMap) ([]LoginLog, error) {
log.parsePageAndPageSize(params)
list := make([]LoginLog, 0)
err := Db.Desc("id").Limit(log.PageSize, log.pageLimitOffset()).Find(&list)
return list, err
}
func (log *LoginLog) Total() (int64, error) {
return Db.Count(log)
}

View File

@ -14,7 +14,7 @@ func (migration *Migration) Exec(dbName string) error {
} }
setting := new(Setting) setting := new(Setting)
tables := []interface{}{ tables := []interface{}{
&User{}, &Task{}, &TaskLog{}, &Host{}, setting, &User{}, &Task{}, &TaskLog{}, &Host{}, setting,&LoginLog{},
} }
for _, table := range tables { for _, table := range tables {
exist, err:= Db.IsTableExist(table) exist, err:= Db.IsTableExist(table)

20
routers/base/base.go Normal file
View File

@ -0,0 +1,20 @@
package base
import (
"gopkg.in/macaron.v1"
"github.com/ouqiang/gocron/models"
)
func ParsePageAndPageSize(ctx *macaron.Context, params models.CommonMap) {
page := ctx.QueryInt("page")
pageSize := ctx.QueryInt("page_size")
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = models.PageSize
}
params["Page"] = page
params["PageSize"] = pageSize
}

View File

@ -11,6 +11,7 @@ import (
"github.com/Unknwon/paginater" "github.com/Unknwon/paginater"
"fmt" "fmt"
"html/template" "html/template"
"github.com/ouqiang/gocron/routers/base"
) )
func Index(ctx *macaron.Context) { func Index(ctx *macaron.Context) {
@ -170,17 +171,7 @@ func parseQueryParams(ctx *macaron.Context) (models.CommonMap) {
var params models.CommonMap = models.CommonMap{} var params models.CommonMap = models.CommonMap{}
params["Id"] = ctx.QueryInt("id") params["Id"] = ctx.QueryInt("id")
params["Name"] = ctx.QueryTrim("name") params["Name"] = ctx.QueryTrim("name")
page := ctx.QueryInt("page") base.ParsePageAndPageSize(ctx, params)
pageSize := ctx.QueryInt("page_size")
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = models.PageSize
}
params["Page"] = page
params["PageSize"] = pageSize
return params return params
} }

View File

@ -0,0 +1,30 @@
package loginlog
import (
"gopkg.in/macaron.v1"
"github.com/Unknwon/paginater"
"fmt"
"github.com/ouqiang/gocron/modules/logger"
"github.com/ouqiang/gocron/models"
"github.com/ouqiang/gocron/routers/base"
"html/template"
)
func Index(ctx *macaron.Context) {
loginLogModel := new(models.LoginLog)
params := models.CommonMap{}
base.ParsePageAndPageSize(ctx, params)
total, err := loginLogModel.Total()
loginLogs, err := loginLogModel.List(params)
if err != nil {
logger.Error(err)
}
PageParams := fmt.Sprintf("page_size=%d", params["PageSize"]);
params["PageParams"] = template.URL(PageParams)
p := paginater.New(int(total), params["PageSize"].(int), params["Page"].(int), 5)
ctx.Data["Pagination"] = p
ctx.Data["Title"] = "登录日志"
ctx.Data["LoginLogs"] = loginLogs
ctx.Data["Params"] = params
ctx.HTML(200, "manage/login_log")
}

View File

@ -1,4 +1,4 @@
package setting package manage
import ( import (
"gopkg.in/macaron.v1" "gopkg.in/macaron.v1"
@ -19,7 +19,7 @@ func EditSlack(ctx *macaron.Context) {
logger.Error(err) logger.Error(err)
} }
ctx.Data["Slack"] = slack ctx.Data["Slack"] = slack
ctx.HTML(200, "setting/slack") ctx.HTML(200, "manage/slack")
} }
func Slack(ctx *macaron.Context) string { func Slack(ctx *macaron.Context) string {
@ -74,7 +74,7 @@ func EditMail(ctx *macaron.Context) {
logger.Error(err) logger.Error(err)
} }
ctx.Data["Mail"] = mail ctx.Data["Mail"] = mail
ctx.HTML(200, "setting/mail") ctx.HTML(200, "manage/mail")
} }
func Mail(ctx *macaron.Context) string { func Mail(ctx *macaron.Context) string {

View File

@ -15,8 +15,9 @@ import (
"github.com/ouqiang/gocron/modules/logger" "github.com/ouqiang/gocron/modules/logger"
"github.com/ouqiang/gocron/routers/user" "github.com/ouqiang/gocron/routers/user"
"github.com/go-macaron/gzip" "github.com/go-macaron/gzip"
"github.com/ouqiang/gocron/routers/setting" "github.com/ouqiang/gocron/routers/manage"
"github.com/go-macaron/csrf" "github.com/go-macaron/csrf"
"github.com/ouqiang/gocron/routers/loginlog"
) )
// 静态文件目录 // 静态文件目录
@ -68,21 +69,22 @@ func Register(m *macaron.Macaron) {
}) })
// 管理 // 管理
m.Group("/setting", func() { m.Group("/manage", func() {
m.Group("/slack", func() { m.Group("/slack", func() {
m.Get("/", setting.Slack) m.Get("/", manage.Slack)
m.Get("/edit", setting.EditSlack) m.Get("/edit", manage.EditSlack)
m.Post("/url", setting.UpdateSlackUrl) m.Post("/url", manage.UpdateSlackUrl)
m.Post("/channel", setting.CreateSlackChannel) m.Post("/channel", manage.CreateSlackChannel)
m.Post("/channel/remove/:id", setting.RemoveSlackChannel) m.Post("/channel/remove/:id", manage.RemoveSlackChannel)
}) })
m.Group("/mail", func() { m.Group("/mail", func() {
m.Get("/", setting.Mail) m.Get("/", manage.Mail)
m.Get("/edit", setting.EditMail) m.Get("/edit", manage.EditMail)
m.Post("/server", binding.Bind(setting.MailServerForm{}), setting.UpdateMailServer) m.Post("/server", binding.Bind(manage.MailServerForm{}), manage.UpdateMailServer)
m.Post("/user", setting.CreateMailUser) m.Post("/user", manage.CreateMailUser)
m.Post("/user/remove/:id", setting.RemoveMailUser) m.Post("/user/remove/:id", manage.RemoveMailUser)
}) })
m.Get("/login-log", loginlog.Index)
}) })
// 404错误 // 404错误

View File

@ -11,6 +11,7 @@ import (
"github.com/Unknwon/paginater" "github.com/Unknwon/paginater"
"fmt" "fmt"
"html/template" "html/template"
"github.com/ouqiang/gocron/routers/base"
) )
type TaskForm struct { type TaskForm struct {
@ -242,17 +243,7 @@ func parseQueryParams(ctx *macaron.Context) (models.CommonMap) {
status -= 1 status -= 1
} }
params["Status"] = status params["Status"] = status
page := ctx.QueryInt("page") base.ParsePageAndPageSize(ctx, params)
pageSize := ctx.QueryInt("page_size")
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = models.PageSize
}
params["Page"] = page
params["PageSize"] = pageSize
return params return params
} }

View File

@ -8,6 +8,7 @@ import (
"github.com/Unknwon/paginater" "github.com/Unknwon/paginater"
"fmt" "fmt"
"html/template" "html/template"
"github.com/ouqiang/gocron/routers/base"
) )
// @author qiang.ou<qingqianludao@gmail.com> // @author qiang.ou<qingqianludao@gmail.com>
@ -58,17 +59,7 @@ func parseQueryParams(ctx *macaron.Context) (models.CommonMap) {
status -= 1 status -= 1
} }
params["Status"] = status params["Status"] = status
page := ctx.QueryInt("page") base.ParsePageAndPageSize(ctx, params)
pageSize := ctx.QueryInt("page_size")
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = models.PageSize
}
params["Page"] = page
params["PageSize"] = pageSize
return params return params
} }

View File

@ -54,12 +54,20 @@ func ValidateLogin(ctx *macaron.Context, sess session.Store) string {
if username == "" || password == "" { if username == "" || password == "" {
return json.CommonFailure("用户名、密码不能为空") return json.CommonFailure("用户名、密码不能为空")
} }
userModel := new (models.User) userModel := new (models.User)
if !userModel.Match(username, password) { if !userModel.Match(username, password) {
return json.CommonFailure("用户名或密码错误") return json.CommonFailure("用户名或密码错误")
} }
loginLogModel := new(models.LoginLog)
loginLogModel.Username = userModel.Name
loginLogModel.Ip = ctx.RemoteAddr()
_, err := loginLogModel.Create()
if err != nil {
logger.Error("记录用户登录日志失败", err)
}
sess.Set("username", userModel.Name) sess.Set("username", userModel.Name)
sess.Set("uid", userModel.Id) sess.Set("uid", userModel.Id)
sess.Set("isAdmin", userModel.IsAdmin) sess.Set("isAdmin", userModel.IsAdmin)

View File

@ -63,7 +63,7 @@
<a class="item {{{if eq .Controller "host"}}}active{{{end}}}" href="/host"><i class="linux icon"></i>主机</a> <a class="item {{{if eq .Controller "host"}}}active{{{end}}}" href="/host"><i class="linux icon"></i>主机</a>
<!-- <a class="item {{{if eq .Controller "user"}}}active{{{end}}}" href="/user"><i class="user icon"></i>账户</a> --> <!-- <a class="item {{{if eq .Controller "user"}}}active{{{end}}}" href="/user"><i class="user icon"></i>账户</a> -->
{{{if gt .LoginUid 0}}} {{{if gt .LoginUid 0}}}
<a class="item {{{if eq .Controller "setting"}}}active{{{end}}}" href="/setting/slack/edit"><i class="settings icon"></i>配置</a> <a class="item {{{if eq .Controller "manage"}}}active{{{end}}}" href="/manage/slack/edit"><i class="settings icon"></i>管理</a>
{{{end}}} {{{end}}}
</div> </div>
</div> </div>

View File

@ -0,0 +1,39 @@
{{{ template "common/header" . }}}
<div class="ui grid">
{{{ template "manage/menu" . }}}
<div class="twelve wide column">
<div class="pageHeader">
<div class="segment">
<h3 class="ui dividing header">
<div class="content">
登录日志
</div>
</h3>
</div>
</div>
<table class="ui striped table">
<thead>
<tr>
<th>用户名</th>
<th>登录IP</th>
<th>登录时间</th>
</tr>
</thead>
<tbody>
{{{range $i, $v := .LoginLogs}}}
<tr>
<td>{{{.Username}}}</td>
<td>{{{.Ip}}}</td>
<td>{{{.Created}}}</td>
</tr>
{{{end}}}
</tbody>
</table>
{{{ template "common/pagination" .}}}
</div>
</div>
{{{ template "common/footer" . }}}

View File

@ -1,6 +1,6 @@
{{{ template "common/header" . }}} {{{ template "common/header" . }}}
<div class="ui grid"> <div class="ui grid">
{{{template "setting/menu" .}}} {{{template "manage/menu" .}}}
<div class="twelve wide column"> <div class="twelve wide column">
<div class="pageHeader"> <div class="pageHeader">
<div class="segment"> <div class="segment">
@ -95,7 +95,7 @@
$('.mail-server').form( $('.mail-server').form(
{ {
onSuccess: function(event, fields) { onSuccess: function(event, fields) {
util.post('/setting/mail/server', util.post('/manage/mail/server',
fields, fields,
function(code, message) { function(code, message) {
util.alertSuccess(); util.alertSuccess();
@ -147,7 +147,7 @@
$('.mail-user').form( $('.mail-user').form(
{ {
onSuccess: function(event, fields) { onSuccess: function(event, fields) {
util.post('/setting/mail/user', util.post('/manage/mail/user',
fields, fields,
function(code, message) { function(code, message) {
util.alertSuccess(); util.alertSuccess();
@ -184,7 +184,7 @@
} }
function removeMailUser(id) { function removeMailUser(id) {
util.post('/setting/mail/user/remove/' + id, {}, function(code, message) { util.post('/manage/mail/user/remove/' + id, {}, function(code, message) {
location.reload(); location.reload();
}); });
} }

View File

@ -0,0 +1,15 @@
<div class="three wide column">
<div class="verticalMenu">
<div class="ui vertical pointing menu fluid">
<a class="{{{if eq .URI "/manage/slack/edit"}}}active teal{{{end}}} item" href="/manage/slack/edit">
<i class="slack icon"></i> Slack配置
</a>
<a class="{{{if eq .URI "/manage/mail/edit"}}}active teal{{{end}}} item" href="/manage/mail/edit">
<i class="slack icon"></i> 邮件配置
</a>
<a class="{{{if eq .URI "/manage/login-log"}}}active teal{{{end}}} item" href="/manage/login-log">
<i class="slack icon"></i> 登录日志
</a>
</div>
</div>
</div>

View File

@ -1,6 +1,6 @@
{{{ template "common/header" . }}} {{{ template "common/header" . }}}
<div class="ui grid"> <div class="ui grid">
{{{template "setting/menu" .}}} {{{template "manage/menu" .}}}
<div class="twelve wide column"> <div class="twelve wide column">
<div class="pageHeader"> <div class="pageHeader">
<div class="segment"> <div class="segment">
@ -47,7 +47,7 @@
methods: { methods: {
updateUrl: function() { updateUrl: function() {
var url = $('#url').val(); var url = $('#url').val();
util.post('/setting/slack/url', {"url": url}, function(code, message) { util.post('/manage/slack/url', {"url": url}, function(code, message) {
util.alertSuccess(); util.alertSuccess();
}); });
}, },
@ -67,7 +67,7 @@
return false return false
} }
util.post('/setting/slack/channel', util.post('/manage/slack/channel',
{"channel": inputValue}, {"channel": inputValue},
function(code, message) { function(code, message) {
util.alertSuccess(); util.alertSuccess();
@ -78,7 +78,7 @@
}); });
}, },
removeChannel: function(id) { removeChannel: function(id) {
util.post('/setting/slack/channel/remove/' + id, {}, function(code, message) { util.post('/manage/slack/channel/remove/' + id, {}, function(code, message) {
location.reload(); location.reload();
}); });
} }

View File

@ -1,12 +0,0 @@
<div class="three wide column">
<div class="verticalMenu">
<div class="ui vertical pointing menu fluid">
<a class="{{{if eq .URI "/setting/slack/edit"}}}active teal{{{end}}} item" href="/setting/slack/edit">
<i class="slack icon"></i> Slack配置
</a>
<a class="{{{if eq .URI "/setting/mail/edit"}}}active teal{{{end}}} item" href="/setting/mail/edit">
<i class="slack icon"></i> 邮件配置
</a>
</div>
</div>
</div>