2016-02-01 12:59:10 +01:00
|
|
|
package controllers
|
|
|
|
|
|
|
|
import (
|
2016-03-31 12:45:26 +02:00
|
|
|
"net/http"
|
2016-02-01 12:59:10 +01:00
|
|
|
"os"
|
2016-06-16 08:10:35 +02:00
|
|
|
"path/filepath"
|
2016-02-01 12:59:10 +01:00
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/astaxie/beego"
|
|
|
|
"github.com/beego/i18n"
|
2016-06-16 08:10:35 +02:00
|
|
|
"github.com/vmware/harbor/auth"
|
2016-03-31 12:45:26 +02:00
|
|
|
"github.com/vmware/harbor/dao"
|
2016-06-16 08:10:35 +02:00
|
|
|
"github.com/vmware/harbor/models"
|
2016-03-31 12:45:26 +02:00
|
|
|
"github.com/vmware/harbor/utils/log"
|
2016-02-01 12:59:10 +01:00
|
|
|
)
|
|
|
|
|
2016-02-26 11:35:55 +01:00
|
|
|
// BaseController wraps common methods such as i18n support, forward, which can be leveraged by other UI render controllers.
|
2016-02-01 12:59:10 +01:00
|
|
|
type BaseController struct {
|
|
|
|
beego.Controller
|
|
|
|
i18n.Locale
|
2016-04-01 09:39:04 +02:00
|
|
|
SelfRegistration bool
|
|
|
|
IsAdmin bool
|
|
|
|
AuthMode string
|
2016-07-14 08:55:36 +02:00
|
|
|
UseCompressedJS bool
|
2016-02-01 12:59:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
type langType struct {
|
|
|
|
Lang string
|
|
|
|
Name string
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
2016-06-16 08:10:35 +02:00
|
|
|
viewPath = "sections"
|
|
|
|
prefixNg = ""
|
2016-02-25 07:40:23 +01:00
|
|
|
defaultLang = "en-US"
|
2016-02-01 12:59:10 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
var supportLanguages map[string]langType
|
2016-06-20 10:05:14 +02:00
|
|
|
var mappingLangNames map[string]string
|
2016-02-01 12:59:10 +01:00
|
|
|
|
2016-02-26 11:35:55 +01:00
|
|
|
// Prepare extracts the language information from request and populate data for rendering templates.
|
2016-02-01 12:59:10 +01:00
|
|
|
func (b *BaseController) Prepare() {
|
|
|
|
|
2016-02-25 07:00:29 +01:00
|
|
|
var lang string
|
2016-02-01 12:59:10 +01:00
|
|
|
|
2016-06-28 17:42:05 +02:00
|
|
|
langCookie, err := b.Ctx.Request.Cookie("language")
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("Error occurred in Request.Cookie: %v", err)
|
|
|
|
}
|
|
|
|
if langCookie != nil {
|
|
|
|
lang = langCookie.Value
|
|
|
|
}
|
|
|
|
if len(lang) == 0 {
|
|
|
|
sessionLang := b.GetSession("lang")
|
|
|
|
if sessionLang != nil {
|
|
|
|
b.SetSession("Lang", lang)
|
|
|
|
lang = sessionLang.(string)
|
|
|
|
} else {
|
2016-06-29 14:47:32 +02:00
|
|
|
al := b.Ctx.Request.Header.Get("Accept-Language")
|
|
|
|
if len(al) > 4 {
|
|
|
|
al = al[:5] // Only compare first 5 letters.
|
|
|
|
if i18n.IsExist(al) {
|
|
|
|
lang = al
|
|
|
|
}
|
|
|
|
}
|
2016-06-28 17:42:05 +02:00
|
|
|
}
|
2016-02-01 12:59:10 +01:00
|
|
|
}
|
|
|
|
|
2016-06-20 10:05:14 +02:00
|
|
|
if _, exist := supportLanguages[lang]; !exist { //Check if support the request language.
|
|
|
|
lang = defaultLang //Set default language if not supported.
|
2016-02-01 12:59:10 +01:00
|
|
|
}
|
|
|
|
|
2016-06-29 14:47:32 +02:00
|
|
|
b.Ctx.SetCookie("language", lang, 0, "/")
|
|
|
|
b.SetSession("Lang", lang)
|
|
|
|
|
2016-06-20 10:05:14 +02:00
|
|
|
curLang := langType{
|
|
|
|
Lang: lang,
|
2016-02-01 12:59:10 +01:00
|
|
|
}
|
|
|
|
|
2016-06-28 17:42:05 +02:00
|
|
|
restLangs := make([]*langType, 0, len(langTypes)-1)
|
|
|
|
for _, v := range langTypes {
|
|
|
|
if lang != v.Lang {
|
|
|
|
restLangs = append(restLangs, v)
|
|
|
|
} else {
|
|
|
|
curLang.Name = v.Name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-01 12:59:10 +01:00
|
|
|
// Set language properties.
|
2016-06-28 17:42:05 +02:00
|
|
|
b.Lang = lang
|
2016-02-01 12:59:10 +01:00
|
|
|
b.Data["Lang"] = curLang.Lang
|
2016-06-28 17:42:05 +02:00
|
|
|
b.Data["CurLang"] = curLang.Name
|
|
|
|
b.Data["RestLangs"] = restLangs
|
2016-02-01 12:59:10 +01:00
|
|
|
|
2016-04-01 09:39:04 +02:00
|
|
|
authMode := strings.ToLower(os.Getenv("AUTH_MODE"))
|
2016-02-01 12:59:10 +01:00
|
|
|
if authMode == "" {
|
|
|
|
authMode = "db_auth"
|
|
|
|
}
|
2016-04-01 09:39:04 +02:00
|
|
|
b.AuthMode = authMode
|
|
|
|
b.Data["AuthMode"] = b.AuthMode
|
2016-03-30 12:02:38 +02:00
|
|
|
|
2016-07-14 08:55:36 +02:00
|
|
|
useCompressedJS := os.Getenv("USE_COMPRESSED_JS")
|
|
|
|
if useCompressedJS == "on" {
|
|
|
|
b.UseCompressedJS = true
|
2016-07-13 11:23:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := os.Stat(filepath.Join("static", "resources", "js", "harbor.app.min.js")); os.IsNotExist(err) {
|
2016-07-14 08:55:36 +02:00
|
|
|
b.UseCompressedJS = false
|
2016-07-13 11:23:43 +02:00
|
|
|
}
|
2016-08-03 09:43:43 +02:00
|
|
|
|
|
|
|
selfRegistration := strings.ToLower(os.Getenv("SELF_REGISTRATION"))
|
|
|
|
if selfRegistration == "on" {
|
|
|
|
b.SelfRegistration = true
|
|
|
|
}
|
|
|
|
b.Data["SelfRegistration"] = b.SelfRegistration
|
2016-06-16 08:10:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Forward to setup layout and template for content for a page.
|
|
|
|
func (b *BaseController) Forward(title, templateName string) {
|
|
|
|
b.Layout = filepath.Join(prefixNg, "layout.htm")
|
|
|
|
b.TplName = filepath.Join(prefixNg, templateName)
|
2016-06-28 17:42:05 +02:00
|
|
|
b.Data["Title"] = b.Tr(title)
|
2016-06-16 08:10:35 +02:00
|
|
|
b.LayoutSections = make(map[string]string)
|
|
|
|
b.LayoutSections["HeaderInclude"] = filepath.Join(prefixNg, viewPath, "header-include.htm")
|
2016-07-13 11:23:43 +02:00
|
|
|
|
2016-07-14 08:55:36 +02:00
|
|
|
if b.UseCompressedJS {
|
2016-07-13 11:23:43 +02:00
|
|
|
b.LayoutSections["HeaderScriptInclude"] = filepath.Join(prefixNg, viewPath, "script-min-include.htm")
|
|
|
|
} else {
|
|
|
|
b.LayoutSections["HeaderScriptInclude"] = filepath.Join(prefixNg, viewPath, "script-include.htm")
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Debugf("Loaded HeaderScriptInclude file: %s", b.LayoutSections["HeaderScriptInclude"])
|
|
|
|
|
2016-06-16 08:10:35 +02:00
|
|
|
b.LayoutSections["FooterInclude"] = filepath.Join(prefixNg, viewPath, "footer-include.htm")
|
|
|
|
b.LayoutSections["HeaderContent"] = filepath.Join(prefixNg, viewPath, "header-content.htm")
|
|
|
|
b.LayoutSections["FooterContent"] = filepath.Join(prefixNg, viewPath, "footer-content.htm")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
var langTypes []*langType
|
|
|
|
|
|
|
|
// CommonController handles request from UI that doesn't expect a page, such as /SwitchLanguage /logout ...
|
|
|
|
type CommonController struct {
|
|
|
|
BaseController
|
|
|
|
}
|
|
|
|
|
|
|
|
// Render returns nil.
|
|
|
|
func (cc *CommonController) Render() error {
|
|
|
|
return nil
|
|
|
|
}
|
2016-03-30 12:02:38 +02:00
|
|
|
|
2016-06-16 08:10:35 +02:00
|
|
|
// Login handles login request from UI.
|
2016-06-16 08:26:33 +02:00
|
|
|
func (cc *CommonController) Login() {
|
|
|
|
principal := cc.GetString("principal")
|
|
|
|
password := cc.GetString("password")
|
2016-06-16 08:10:35 +02:00
|
|
|
|
|
|
|
user, err := auth.Login(models.AuthModel{
|
|
|
|
Principal: principal,
|
|
|
|
Password: password,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("Error occurred in UserLogin: %v", err)
|
2016-06-16 08:26:33 +02:00
|
|
|
cc.CustomAbort(http.StatusUnauthorized, "")
|
2016-03-30 14:00:14 +02:00
|
|
|
}
|
|
|
|
|
2016-06-16 08:10:35 +02:00
|
|
|
if user == nil {
|
2016-06-16 08:26:33 +02:00
|
|
|
cc.CustomAbort(http.StatusUnauthorized, "")
|
2016-03-30 12:02:38 +02:00
|
|
|
}
|
|
|
|
|
2016-06-16 08:26:33 +02:00
|
|
|
cc.SetSession("userId", user.UserID)
|
|
|
|
cc.SetSession("username", user.Username)
|
2016-06-16 08:10:35 +02:00
|
|
|
}
|
2016-03-30 12:02:38 +02:00
|
|
|
|
2016-06-16 08:10:35 +02:00
|
|
|
// LogOut Habor UI
|
|
|
|
func (cc *CommonController) LogOut() {
|
|
|
|
cc.DestroySession()
|
2016-02-01 12:59:10 +01:00
|
|
|
}
|
|
|
|
|
2016-06-16 08:10:35 +02:00
|
|
|
// SwitchLanguage User can swith to prefered language
|
|
|
|
func (cc *CommonController) SwitchLanguage() {
|
|
|
|
lang := cc.GetString("lang")
|
2016-06-28 17:42:05 +02:00
|
|
|
hash := cc.GetString("hash")
|
2016-06-20 10:05:14 +02:00
|
|
|
if _, exist := supportLanguages[lang]; !exist {
|
|
|
|
lang = defaultLang
|
2016-06-16 08:10:35 +02:00
|
|
|
}
|
2016-06-20 10:05:14 +02:00
|
|
|
cc.SetSession("lang", lang)
|
|
|
|
cc.Data["Lang"] = lang
|
2016-06-28 17:42:05 +02:00
|
|
|
cc.Redirect(cc.Ctx.Request.Header.Get("Referer")+hash, http.StatusFound)
|
2016-02-01 12:59:10 +01:00
|
|
|
}
|
|
|
|
|
2016-06-16 08:10:35 +02:00
|
|
|
// UserExists checks if user exists when user input value in sign in form.
|
|
|
|
func (cc *CommonController) UserExists() {
|
|
|
|
target := cc.GetString("target")
|
|
|
|
value := cc.GetString("value")
|
|
|
|
|
|
|
|
user := models.User{}
|
|
|
|
switch target {
|
|
|
|
case "username":
|
|
|
|
user.Username = value
|
|
|
|
case "email":
|
|
|
|
user.Email = value
|
|
|
|
}
|
|
|
|
|
|
|
|
exist, err := dao.UserExists(user, target)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("Error occurred in UserExists: %v", err)
|
|
|
|
cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
|
|
|
}
|
|
|
|
cc.Data["json"] = exist
|
|
|
|
cc.ServeJSON()
|
|
|
|
}
|
2016-02-01 12:59:10 +01:00
|
|
|
|
|
|
|
func init() {
|
|
|
|
|
2016-02-23 05:16:36 +01:00
|
|
|
//conf/app.conf -> os.Getenv("config_path")
|
|
|
|
configPath := os.Getenv("CONFIG_PATH")
|
|
|
|
if len(configPath) != 0 {
|
2016-03-31 05:29:04 +02:00
|
|
|
log.Infof("Config path: %s", configPath)
|
2016-06-27 11:38:50 +02:00
|
|
|
beego.LoadAppConfig("ini", configPath)
|
2016-02-23 05:16:36 +01:00
|
|
|
}
|
|
|
|
|
2016-06-28 17:42:05 +02:00
|
|
|
beego.AddFuncMap("i18n", i18n.Tr)
|
|
|
|
|
2016-02-01 12:59:10 +01:00
|
|
|
langs := strings.Split(beego.AppConfig.String("lang::types"), "|")
|
|
|
|
names := strings.Split(beego.AppConfig.String("lang::names"), "|")
|
|
|
|
|
|
|
|
supportLanguages = make(map[string]langType)
|
|
|
|
|
|
|
|
langTypes = make([]*langType, 0, len(langs))
|
2016-06-28 17:42:05 +02:00
|
|
|
|
|
|
|
for i, lang := range langs {
|
2016-02-01 12:59:10 +01:00
|
|
|
t := langType{
|
2016-06-28 17:42:05 +02:00
|
|
|
Lang: lang,
|
2016-02-01 12:59:10 +01:00
|
|
|
Name: names[i],
|
|
|
|
}
|
|
|
|
langTypes = append(langTypes, &t)
|
2016-06-28 17:42:05 +02:00
|
|
|
supportLanguages[lang] = t
|
|
|
|
if err := i18n.SetMessage(lang, "static/i18n/"+"locale_"+lang+".ini"); err != nil {
|
|
|
|
log.Errorf("Fail to set message file: %s", err.Error())
|
|
|
|
}
|
2016-02-01 12:59:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|