mirror of
https://github.com/kataras/iris.git
synced 2025-03-22 14:36:26 +01:00
190 lines
5.5 KiB
Go
190 lines
5.5 KiB
Go
package user
|
|
|
|
import (
|
|
"github.com/kataras/iris"
|
|
"github.com/kataras/iris/mvc"
|
|
)
|
|
|
|
var (
|
|
// About Code: iris.StatusSeeOther ->
|
|
// 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.
|
|
// "See Other" RFC 7231
|
|
pathMyProfile = mvc.Response{Path: "/user/me", Code: iris.StatusSeeOther}
|
|
pathRegister = mvc.Response{Path: "/user/register"}
|
|
)
|
|
|
|
// Controller is responsible to handle the following requests:
|
|
// GET /user/register
|
|
// POST /user/register
|
|
// GET /user/login
|
|
// POST /user/login
|
|
// GET /user/me
|
|
// GET /user/{id:long} | long is a new param type, it's the int64.
|
|
// All HTTP Methods /user/logout
|
|
type Controller struct {
|
|
AuthController
|
|
}
|
|
|
|
type formValue func(string) string
|
|
|
|
// BeforeActivation called once before the server start
|
|
// and before the controller's registration, here you can add
|
|
// dependencies, to this controller and only, that the main caller may skip.
|
|
func (c *Controller) BeforeActivation(b mvc.BeforeActivation) {
|
|
// bind the context's `FormValue` as well in order to be
|
|
// acceptable on the controller or its methods' input arguments (NEW feature as well).
|
|
b.Dependencies().Add(func(ctx iris.Context) formValue { return ctx.FormValue })
|
|
}
|
|
|
|
type page struct {
|
|
Title string
|
|
}
|
|
|
|
// GetRegister handles GET:/user/register.
|
|
// mvc.Result can accept any struct which contains a `Dispatch(ctx iris.Context)` method.
|
|
// Both mvc.Response and mvc.View are mvc.Result.
|
|
func (c *Controller) GetRegister() mvc.Result {
|
|
if c.isLoggedIn() {
|
|
return c.logout()
|
|
}
|
|
|
|
// You could just use it as a variable to win some time in serve-time,
|
|
// this is an exersise for you :)
|
|
return mvc.View{
|
|
Name: pathRegister.Path + ".html",
|
|
Data: page{"User Registration"},
|
|
}
|
|
}
|
|
|
|
// PostRegister handles POST:/user/register.
|
|
func (c *Controller) PostRegister(form formValue) mvc.Result {
|
|
// we can either use the `c.Ctx.ReadForm` or read values one by one.
|
|
var (
|
|
firstname = form("firstname")
|
|
username = form("username")
|
|
password = form("password")
|
|
)
|
|
|
|
user, err := c.createOrUpdate(firstname, username, password)
|
|
if err != nil {
|
|
return c.fireError(err)
|
|
}
|
|
|
|
// setting a session value was never easier.
|
|
c.Session.Set(sessionIDKey, user.ID)
|
|
// succeed, nothing more to do here, just redirect to the /user/me.
|
|
return pathMyProfile
|
|
}
|
|
|
|
// with these static views,
|
|
// you can use variables-- that are initialized before server start
|
|
// so you can win some time on serving.
|
|
// You can do it else where as well but I let them as pracise for you,
|
|
// essentialy you can understand by just looking below.
|
|
var userLoginView = mvc.View{
|
|
Name: PathLogin.Path + ".html",
|
|
Data: page{"User Login"},
|
|
}
|
|
|
|
// GetLogin handles GET:/user/login.
|
|
func (c *Controller) GetLogin() mvc.Result {
|
|
if c.isLoggedIn() {
|
|
return c.logout()
|
|
}
|
|
return userLoginView
|
|
}
|
|
|
|
// PostLogin handles POST:/user/login.
|
|
func (c *Controller) PostLogin(form formValue) mvc.Result {
|
|
var (
|
|
username = form("username")
|
|
password = form("password")
|
|
)
|
|
|
|
user, err := c.verify(username, password)
|
|
if err != nil {
|
|
return c.fireError(err)
|
|
}
|
|
|
|
c.Session.Set(sessionIDKey, user.ID)
|
|
return pathMyProfile
|
|
}
|
|
|
|
// AnyLogout handles any method on path /user/logout.
|
|
func (c *Controller) AnyLogout() {
|
|
c.logout()
|
|
}
|
|
|
|
// GetMe handles GET:/user/me.
|
|
func (c *Controller) GetMe() mvc.Result {
|
|
id, err := c.Session.GetInt64(sessionIDKey)
|
|
if err != nil || id <= 0 {
|
|
// when not already logged in, redirect to login.
|
|
return PathLogin
|
|
}
|
|
|
|
u, found := c.Source.GetByID(id)
|
|
if !found {
|
|
// if the session exists but for some reason the user doesn't exist in the "database"
|
|
// then logout him and redirect to the register page.
|
|
return c.logout()
|
|
}
|
|
|
|
// set the model and render the view template.
|
|
return mvc.View{
|
|
Name: pathMyProfile.Path + ".html",
|
|
Data: iris.Map{
|
|
"Title": "Profile of " + u.Username,
|
|
"User": u,
|
|
},
|
|
}
|
|
}
|
|
|
|
func (c *Controller) renderNotFound(id int64) mvc.View {
|
|
return mvc.View{
|
|
Code: iris.StatusNotFound,
|
|
Name: "user/notfound.html",
|
|
Data: iris.Map{
|
|
"Title": "User Not Found",
|
|
"ID": id,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Dispatch completes the `mvc.Result` interface
|
|
// in order to be able to return a type of `Model`
|
|
// as mvc.Result.
|
|
// If this function didn't exist then
|
|
// we should explicit set the output result to that Model or to an interface{}.
|
|
func (u Model) Dispatch(ctx iris.Context) {
|
|
ctx.JSON(u)
|
|
}
|
|
|
|
// GetBy handles GET:/user/{id:long},
|
|
// i.e http://localhost:8080/user/1
|
|
func (c *Controller) GetBy(userID int64) mvc.Result {
|
|
// we have /user/{id}
|
|
// fetch and render user json.
|
|
user, found := c.Source.GetByID(userID)
|
|
if !found {
|
|
// not user found with that ID.
|
|
return c.renderNotFound(userID)
|
|
}
|
|
|
|
// Q: how the hell Model can be return as mvc.Result?
|
|
// A: I told you before on some comments and the docs,
|
|
// any struct that has a `Dispatch(ctx iris.Context)`
|
|
// can be returned as an mvc.Result(see ~20 lines above),
|
|
// therefore we are able to combine many type of results in the same method.
|
|
// For example, here, we return either an mvc.View to render a not found custom template
|
|
// either a user which returns the Model as JSON via its Dispatch.
|
|
//
|
|
// We could also return just a struct value that is not an mvc.Result,
|
|
// if the output result of the `GetBy` was that struct's type or an interface{}
|
|
// and iris would render that with JSON as well, but here we can't do that without complete the `Dispatch`
|
|
// function, because we may return an mvc.View which is an mvc.Result.
|
|
return user
|
|
}
|