mirror of
https://github.com/kataras/iris.git
synced 2025-12-20 03:17:04 +00:00
Update the _examples/mvc/login example - add a Path property at mvc.Response and add a context.Proceed helper function
Former-commit-id: b898901fe4a324e888a6e09c93530cf7a551cf2a
This commit is contained in:
189
_examples/mvc/login/web/controllers/user_controller.go
Normal file
189
_examples/mvc/login/web/controllers/user_controller.go
Normal file
@@ -0,0 +1,189 @@
|
||||
// file: controllers/user_controller.go
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/_examples/mvc/login/datamodels"
|
||||
"github.com/kataras/iris/_examples/mvc/login/services"
|
||||
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/mvc"
|
||||
"github.com/kataras/iris/sessions"
|
||||
)
|
||||
|
||||
// UserController is our /user controller.
|
||||
// UserController is responsible to handle the following requests:
|
||||
// GET /user/register
|
||||
// POST /user/register
|
||||
// GET /user/login
|
||||
// POST /user/login
|
||||
// GET /user/me
|
||||
// All HTTP Methods /user/logout
|
||||
type UserController struct {
|
||||
// mvc.C is just a lightweight lightweight alternative
|
||||
// to the "mvc.Controller" controller type,
|
||||
// use it when you don't need mvc.Controller's fields
|
||||
// (you don't need those fields when you return values from the method functions).
|
||||
mvc.C
|
||||
|
||||
// Our UserService, it's an interface which
|
||||
// is binded from the main application.
|
||||
Service services.UserService
|
||||
|
||||
// Session-relative things.
|
||||
Manager *sessions.Sessions
|
||||
Session *sessions.Session
|
||||
}
|
||||
|
||||
// BeginRequest will set the current session to the controller.
|
||||
//
|
||||
// Remember: iris.Context and context.Context is exactly the same thing,
|
||||
// iris.Context is just a type alias for go 1.9 users.
|
||||
// We use context.Context here because we don't need all iris' root functions,
|
||||
// when we see the import paths, we make it visible to ourselves that this file is using only the context.
|
||||
func (c *UserController) BeginRequest(ctx context.Context) {
|
||||
c.C.BeginRequest(ctx)
|
||||
|
||||
if c.Manager == nil {
|
||||
ctx.Application().Logger().Errorf(`UserController: sessions manager is nil, you should bind it`)
|
||||
ctx.StopExecution() // dont run the main method handler and any "done" handlers.
|
||||
return
|
||||
}
|
||||
|
||||
c.Session = c.Manager.Start(ctx)
|
||||
}
|
||||
|
||||
const userIDKey = "UserID"
|
||||
|
||||
func (c *UserController) getCurrentUserID() int64 {
|
||||
userID, _ := c.Session.GetInt64Default(userIDKey, 0)
|
||||
return userID
|
||||
}
|
||||
|
||||
func (c *UserController) isLoggedIn() bool {
|
||||
return c.getCurrentUserID() > 0
|
||||
}
|
||||
|
||||
func (c *UserController) logout() {
|
||||
c.Manager.DestroyByID(c.Session.ID())
|
||||
}
|
||||
|
||||
var registerStaticView = mvc.View{
|
||||
Name: "user/register.html",
|
||||
Data: context.Map{"Title": "User Registration"},
|
||||
}
|
||||
|
||||
// GetRegister handles GET: http://localhost:8080/user/register.
|
||||
func (c *UserController) GetRegister() mvc.Result {
|
||||
if c.isLoggedIn() {
|
||||
c.logout()
|
||||
}
|
||||
|
||||
return registerStaticView
|
||||
}
|
||||
|
||||
// PostRegister handles POST: http://localhost:8080/user/register.
|
||||
func (c *UserController) PostRegister() mvc.Result {
|
||||
// get firstname, username and password from the form.
|
||||
var (
|
||||
firstname = c.Ctx.FormValue("firstname")
|
||||
username = c.Ctx.FormValue("username")
|
||||
password = c.Ctx.FormValue("password")
|
||||
)
|
||||
|
||||
// create the new user, the password will be hashed by the service.
|
||||
u, err := c.Service.Create(password, datamodels.User{
|
||||
Username: username,
|
||||
Firstname: firstname,
|
||||
})
|
||||
|
||||
// set the user's id to this session even if err != nil,
|
||||
// the zero id doesn't matters because .getCurrentUserID() checks for that.
|
||||
// If err != nil then it will be shown, see below on mvc.Response.Err: err.
|
||||
c.Session.Set(userIDKey, u.ID)
|
||||
|
||||
return mvc.Response{
|
||||
// if not nil then this error will be shown instead.
|
||||
Err: err,
|
||||
// redirect to /user/me.
|
||||
Path: "/user/me",
|
||||
// When redirecting from POST to GET request you -should- use this HTTP status code,
|
||||
// however there're some (complicated) alternatives if you
|
||||
// search online or even the HTTP RFC.
|
||||
// Status "See Other" RFC 7231, however iris can automatically fix that
|
||||
// but it's good to know you can set a custom code;
|
||||
// Code: 303,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var loginStaticView = mvc.View{
|
||||
Name: "user/login.html",
|
||||
Data: context.Map{"Title": "User Login"},
|
||||
}
|
||||
|
||||
// GetLogin handles GET: http://localhost:8080/user/login.
|
||||
func (c *UserController) GetLogin() mvc.Result {
|
||||
if c.isLoggedIn() {
|
||||
// if it's already logged in then destroy the previous session.
|
||||
c.logout()
|
||||
}
|
||||
|
||||
return loginStaticView
|
||||
}
|
||||
|
||||
// PostLogin handles POST: http://localhost:8080/user/register.
|
||||
func (c *UserController) PostLogin() mvc.Result {
|
||||
var (
|
||||
username = c.Ctx.FormValue("username")
|
||||
password = c.Ctx.FormValue("password")
|
||||
)
|
||||
|
||||
u, found := c.Service.GetByUsernameAndPassword(username, password)
|
||||
|
||||
if !found {
|
||||
return mvc.Response{
|
||||
Path: "/user/register",
|
||||
}
|
||||
}
|
||||
|
||||
c.Session.Set(userIDKey, u.ID)
|
||||
|
||||
return mvc.Response{
|
||||
Path: "/user/me",
|
||||
}
|
||||
}
|
||||
|
||||
// GetMe handles GET: http://localhost:8080/user/me.
|
||||
func (c *UserController) GetMe() mvc.Result {
|
||||
if !c.isLoggedIn() {
|
||||
// if it's not logged in then redirect user to the login page.
|
||||
return mvc.Response{Path: "/user/login"}
|
||||
}
|
||||
|
||||
u, found := c.Service.GetByID(c.getCurrentUserID())
|
||||
if !found {
|
||||
// if the session exists but for some reason the user doesn't exist in the "database"
|
||||
// then logout and re-execute the function, it will redirect the client to the
|
||||
// /user/login page.
|
||||
c.logout()
|
||||
return c.GetMe()
|
||||
}
|
||||
|
||||
return mvc.View{
|
||||
Name: "user/me.html",
|
||||
Data: context.Map{
|
||||
"Title": "Profile of " + u.Username,
|
||||
"User": u,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// AnyLogout handles All/Any HTTP Methods for: http://localhost:8080/user/logout.
|
||||
func (c *UserController) AnyLogout() {
|
||||
if c.isLoggedIn() {
|
||||
c.logout()
|
||||
}
|
||||
|
||||
c.Ctx.Redirect("/user/login")
|
||||
}
|
||||
101
_examples/mvc/login/web/controllers/users_controller.go
Normal file
101
_examples/mvc/login/web/controllers/users_controller.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris/_examples/mvc/login/datamodels"
|
||||
"github.com/kataras/iris/_examples/mvc/login/services"
|
||||
|
||||
"github.com/kataras/iris/mvc"
|
||||
)
|
||||
|
||||
// UsersController is our /users API controller.
|
||||
// GET /users | get all
|
||||
// GET /users/{id:long} | get by id
|
||||
// PUT /users/{id:long} | update by id
|
||||
// DELETE /users/{id:long} | delete by id
|
||||
// Requires basic authentication.
|
||||
type UsersController struct {
|
||||
mvc.C
|
||||
|
||||
Service services.UserService
|
||||
}
|
||||
|
||||
// This could be possible but we should not call handlers inside the `BeginRequest`.
|
||||
// Because `BeginRequest` was introduced to set common, shared variables between all method handlers
|
||||
// before their execution.
|
||||
// We will add this middleware from our `app.Controller` call.
|
||||
//
|
||||
// var authMiddleware = basicauth.New(basicauth.Config{
|
||||
// Users: map[string]string{
|
||||
// "admin": "password",
|
||||
// },
|
||||
// })
|
||||
//
|
||||
// func (c *UsersController) BeginRequest(ctx iris.Context) {
|
||||
// c.C.BeginRequest(ctx)
|
||||
//
|
||||
// if !ctx.Proceed(authMiddleware) {
|
||||
// ctx.StopExecution()
|
||||
// }
|
||||
// }
|
||||
|
||||
// Get returns list of the users.
|
||||
// Demo:
|
||||
// curl -i -u admin:password http://localhost:8080/users
|
||||
//
|
||||
// The correct way if you have sensitive data:
|
||||
// func (c *UsersController) Get() (results []viewmodels.User) {
|
||||
// data := c.Service.GetAll()
|
||||
//
|
||||
// for _, user := range data {
|
||||
// results = append(results, viewmodels.User{user})
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
// otherwise just return the datamodels.
|
||||
func (c *UsersController) Get() (results []datamodels.User) {
|
||||
return c.Service.GetAll()
|
||||
}
|
||||
|
||||
// GetBy returns a user.
|
||||
// Demo:
|
||||
// curl -i -u admin:password http://localhost:8080/users/1
|
||||
func (c *UsersController) GetBy(id int64) (user datamodels.User, found bool) {
|
||||
u, found := c.Service.GetByID(id)
|
||||
if !found {
|
||||
// this message will be binded to the
|
||||
// main.go -> app.OnAnyErrorCode -> NotFound -> shared/error.html -> .Message text.
|
||||
c.Ctx.Values().Set("message", "User couldn't be found!")
|
||||
}
|
||||
return u, found // it will throw/emit 404 if found == false.
|
||||
}
|
||||
|
||||
// PutBy updates a user.
|
||||
// Demo:
|
||||
// curl -i -X PUT -u admin:password -F "username=kataras"
|
||||
// -F "password=rawPasswordIsNotSafeIfOrNotHTTPs_You_Should_Use_A_client_side_lib_for_hash_as_well"
|
||||
// http://localhost:8080/users/1
|
||||
func (c *UsersController) PutBy(id int64) (datamodels.User, error) {
|
||||
// username := c.Ctx.FormValue("username")
|
||||
// password := c.Ctx.FormValue("password")
|
||||
u := datamodels.User{}
|
||||
if err := c.Ctx.ReadForm(&u); err != nil {
|
||||
return u, err
|
||||
}
|
||||
|
||||
return c.Service.Update(id, u)
|
||||
}
|
||||
|
||||
// DeleteBy deletes a user.
|
||||
// Demo:
|
||||
// curl -i -X DELETE -u admin:password http://localhost:8080/users/1
|
||||
func (c *UsersController) DeleteBy(id int64) interface{} {
|
||||
wasDel := c.Service.DeleteByID(id)
|
||||
if wasDel {
|
||||
// return the deleted user's ID
|
||||
return map[string]interface{}{"deleted": id}
|
||||
}
|
||||
// right here we can see that a method function
|
||||
// can return any of those two types(map or int),
|
||||
// we don't have to specify the return type to a specific type.
|
||||
return 400 // same as `iris.StatusBadRequest`.
|
||||
}
|
||||
Reference in New Issue
Block a user