Skip to content
Permalink
Browse files

Still working on QOR

  • Loading branch information...
Depado committed Feb 13, 2019
1 parent 9bd7f24 commit aba931d1cd3d41dd89b0966fed3091abf420dd7f
@@ -0,0 +1,75 @@
package admin

import (
"path/filepath"

"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
"github.com/qor/admin"
"github.com/qor/qor"
"github.com/qor/qor/resource"
"github.com/qor/validations"
"golang.org/x/crypto/bcrypt"

"github.com/Depado/articles/code/qor/v1/models"
)

type Admin struct {
db *gorm.DB
auth auth
adm *admin.Admin
adminpath string
prefix string
}

func New(db *gorm.DB, prefix, cookiesecret string) *Admin {
adminpath := filepath.Join(prefix, "/admin")
a := Admin{
db: db,
prefix: prefix,
adminpath: adminpath,
auth: auth{
db: db,
paths: pathConfig{
admin: adminpath,
login: filepath.Join(prefix, "/login"),
logout: filepath.Join(prefix, "/logout"),
},
session: sessionConfig{
key: "userid",
name: "admsession",
store: cookie.NewStore([]byte(cookiesecret)),
},
},
}
a.adm = admin.New(&admin.AdminConfig{SiteName: "My Admin Interface", DB: db, Auth: a.auth})

a.adm.AddResource(&models.Product{})
usr := a.adm.AddResource(&models.AdminUser{}, &admin.Config{Menu: []string{"User Management"}})
usr.IndexAttrs("-Password")
usr.Meta(&admin.Meta{
Name: "Password",
Type: "password",
Setter: func(resource interface{}, metaValue *resource.MetaValue, context *qor.Context) {
values := metaValue.Value.([]string)
if len(values) > 0 {
if np := values[0]; np != "" {
pwd, err := bcrypt.GenerateFromPassword([]byte(np), bcrypt.DefaultCost)
if err != nil {
context.DB.AddError(validations.NewError(usr, "Password", "Can't encrypt password")) // nolint: gosec,errcheck
return
}
u := resource.(*models.AdminUser)
u.Password = pwd
}
}
},
})

return &a
}

func (a Admin) Bind(r *gin.Engine) {

}
@@ -1,33 +1,101 @@
package admin

import (
"github.com/Depado/articles/code/qor/v1/models"
"net/http"
"time"

"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
"github.com/qor/admin"
"github.com/qor/qor"
"github.com/sirupsen/logrus"

"github.com/Depado/articles/code/qor/v1/models"
)

// Auth is a structure to handle authentication for QOR. It will satisify the
// qor.Auth interface.
type Auth struct {
db *gorm.DB
type auth struct {
db *gorm.DB
session sessionConfig
paths pathConfig
}

type sessionConfig struct {
name string
key string
store cookie.Store
}

type pathConfig struct {
login string
logout string
admin string
}

login string
logout string
session string
key string
// GetLogin simply returns the login page
func (a *auth) GetLogin(c *gin.Context) {
if sessions.Default(c).Get(a.session.key) != nil {
c.Redirect(http.StatusSeeOther, a.paths.admin)
return
}
c.HTML(http.StatusOK, "login", gin.H{})
}

// PostLogin is the handler to check if the user can connect
func (a *auth) PostLogin(c *gin.Context) {
session := sessions.Default(c)
email := c.PostForm("email")
password := c.PostForm("password")
if email == "" || password == "" {
c.Redirect(http.StatusSeeOther, a.paths.login)
return
}
var u models.AdminUser
if a.db.Where(&models.AdminUser{Email: email}).First(&u).RecordNotFound() {
c.Redirect(http.StatusSeeOther, a.paths.login)
return
}
if !u.CheckPassword(password) {
c.Redirect(http.StatusSeeOther, a.paths.login)
return
}

now := time.Now()
u.LastLogin = &now
a.db.Save(&u)

session.Set(a.session.key, u.ID)
err := session.Save()
if err != nil {
logrus.WithError(err).Warn("Couldn't save session")
c.Redirect(http.StatusSeeOther, a.paths.login)
return
}
c.Redirect(http.StatusSeeOther, a.paths.admin)
}

// GetLogout allows the user to disconnect
func (a *auth) GetLogout(c *gin.Context) {
session := sessions.Default(c)
session.Delete(a.session.key)
if err := session.Save(); err != nil {
logrus.WithError(err).Warn("Couldn't save session")
}
c.Redirect(http.StatusSeeOther, a.paths.login)
}

// GetCurrentUser satisfies the Auth interface and returns the current user
func (a Auth) GetCurrentUser(c *admin.Context) qor.CurrentUser {
func (a auth) GetCurrentUser(c *admin.Context) qor.CurrentUser {
var userid uint
s, err := a.store.Get(c.Request, a.session)

s, err := a.session.store.Get(c.Request, a.session.name)
if err != nil {
return nil
}
if v, ok := s.Values[a.key]; ok {
if v, ok := s.Values[a.session.key]; ok {
userid = v.(uint)
} else {
return nil
@@ -43,12 +111,12 @@ func (a Auth) GetCurrentUser(c *admin.Context) qor.CurrentUser {

// LoginURL statisfies the Auth interface and returns the route used to log
// users in
func (a Auth) LoginURL(c *admin.Context) string { // nolint: unparam
return "/login"
func (a auth) LoginURL(c *admin.Context) string { // nolint: unparam
return a.paths.login
}

// LogoutURL statisfies the Auth interface and returns the route used to logout
// a user
func (a Auth) LogoutURL(c *admin.Context) string { // nolint: unparam
return "/logout"
func (a auth) LogoutURL(c *admin.Context) string { // nolint: unparam
return a.paths.logout
}
@@ -0,0 +1,60 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Login</title>
<link rel="stylesheet" href="https://unpkg.com/spectre.css/dist/spectre.min.css">
<link rel="stylesheet" href="https://unpkg.com/spectre.css/dist/spectre-icons.min.css">
</head>

<style>
html {
height: 100vh;
}
body {
display: flex;
flex-direction: column;
height: 100vh;
}
form {
flex: 1 0 auto;
}
form .has-icon-left {
margin-bottom: 5px;
}
form .btn {
width: 100%;
}
.container {
height: 100%;
}
.columns {
height: 100%;
}
</style>

<body>
<div class="container">
<div class="columns">
<div class="col-4 col-mx-auto flex-centered">
<form method="POST">
<div class="has-icon-left">
<input class="form-input" name="email" type="mail" placeholder="Email">
<i class="form-icon icon icon-mail"></i>
</div>
<div class="has-icon-left">
<input class="form-input" name="password" type="password" placeholder="Password">
<i class="form-icon icon icon-more-horiz"></i>
</div>

<button class="btn btn-primary input-group-btn">Submit</button>
</form>
</div>
</div>
</div>
</body>

</html>
@@ -7,14 +7,9 @@ import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres"
"github.com/qor/admin"
"github.com/qor/qor"
"github.com/qor/qor/resource"
"github.com/qor/validations"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/bcrypt"

"github.com/Depado/articles/code/qor/v1/migrate"
"github.com/Depado/articles/code/qor/v1/models"
)

func main() {
@@ -35,28 +30,6 @@ func main() {
mux := http.NewServeMux()
adm.MountTo("/admin", mux)

adm.AddResource(&models.Product{})
usr := adm.AddResource(&models.AdminUser{}, &admin.Config{Menu: []string{"User Management"}})
usr.IndexAttrs("-Password")
usr.Meta(&admin.Meta{
Name: "Password",
Type: "password",
Setter: func(resource interface{}, metaValue *resource.MetaValue, context *qor.Context) {
values := metaValue.Value.([]string)
if len(values) > 0 {
if np := values[0]; np != "" {
pwd, err := bcrypt.GenerateFromPassword([]byte(np), bcrypt.DefaultCost)
if err != nil {
context.DB.AddError(validations.NewError(usr, "Password", "Can't encrypt password")) // nolint: gosec,errcheck
return
}
u := resource.(*models.AdminUser)
u.Password = pwd
}
}
},
})

r := gin.New()
r.Any("/admin/*resources", gin.WrapH(mux))
r.Run("127.0.0.1:8080")

0 comments on commit aba931d

Please sign in to comment.
You can’t perform that action at this time.