// 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") }