diff --git a/.gitignore b/.gitignore index c4a651b..cc1ef70 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ !/webroot +!/web_webroot +cmd/warehost/warehost +cmd/warehost-web/warehost-web test.log config.yml diff --git a/cmd/warehost-web/config.go b/cmd/warehost-web/config.go new file mode 100644 index 0000000..d04a164 --- /dev/null +++ b/cmd/warehost-web/config.go @@ -0,0 +1,30 @@ +package main + +import ( + "io/ioutil" + "log" + + "gopkg.in/yaml.v2" +) + +type Config struct { + Address string `yaml:"address"` + Port string `yaml:"port"` + Webroot string `yaml:"webroot"` + Database string `yaml:"database"` + Log struct { + Path string `yaml:"path"` + } `yaml:"log"` + DatabaseDebug bool `yaml:"databasedebug"` +} + +// ReadConfigFile reads a config models by path to a yml file +func ReadConfigFile(path string) *Config { + config := &Config{} + file, _ := ioutil.ReadFile(path) + err := yaml.Unmarshal(file, &config) + if err != nil { + log.Fatal(err) + } + return config +} diff --git a/cmd/warehost-web/config.yml.example b/cmd/warehost-web/config.yml.example new file mode 100644 index 0000000..f7904fc --- /dev/null +++ b/cmd/warehost-web/config.yml.example @@ -0,0 +1,8 @@ +--- +address: ::1 +port: 8082 +webroot: ../../web_webroot/ +database: "host=localhost user=warehost dbname=warehost password=hallo sslmode=disable" +log: + path: test.log +databasedebug: false diff --git a/cmd/warehost-web/handler.go b/cmd/warehost-web/handler.go new file mode 100644 index 0000000..087a1aa --- /dev/null +++ b/cmd/warehost-web/handler.go @@ -0,0 +1,76 @@ +package main + +import ( + "fmt" + "net/http" + "os" + "text/template" + + "github.com/microcosm-cc/bluemonday" + "github.com/russross/blackfriday" + + log "dev.sum7.de/sum7/warehost/lib/log" + modul "dev.sum7.de/sum7/warehost/modul/web" +) + +//ProxyHost if this server is behind a proxy +const ProxyHost = "X-Real-Host" + +func getWebsite(host string) *modul.Website { + website := &modul.Website{} + dbconnection.Model(website).Joins("JOIN web_domain ON web_domain.website = web_website.id").Where("web_domain.name = ?", host).First(website) + return website +} + +func handlerstatic(w http.ResponseWriter, r *http.Request) { + host := r.Header.Get(ProxyHost) + if len(host) <= 1 { + host = r.Host + } + website := getWebsite(host) + + path := fmt.Sprintf("%s/%d/%s/%s", config.Webroot, website.ID, "files", r.URL.Path) + if f, err := os.Stat(path); err == nil && !f.IsDir() { + http.ServeFile(w, r, path) + return + } + + http.NotFound(w, r) +} +func handlerfunc(w http.ResponseWriter, r *http.Request) { + host := r.Header.Get(ProxyHost) + if len(host) <= 1 { + host = r.Host + } + url := r.URL.Path[1:] + logger := log.NewModulLog(host).GetLog(r, url) + website := getWebsite(host) + logger = logger.WithField("hID", website.ID) + + var menus []*modul.Menu + dbconnection.Where("website = ? AND menu IS NULL", website.ID).Preload("Menu").Find(&menus) + var menu *modul.Menu + for _, item := range menus { + if item.Shorturl == "" && menu == nil { + menu = item + } + if item.Shorturl == url { + menu = item + } + } + page := &modul.Page{WebsiteID: website.ID, MenuID: menu.ID} + dbconnection.Where(page).Find(page) + logger.Info(page.ID) + + unsafe := blackfriday.MarkdownCommon([]byte(page.Content)) + page.Content = string(bluemonday.UGCPolicy().SanitizeBytes(unsafe)) + i := TemplateInfo{ + Host: host, + URL: url, + Page: page, + Menu: menus, + } + t, _ := template.ParseGlob(fmt.Sprintf("%s/%d/%s/%s", config.Webroot, website.ID, "tmpl", "*.tmpl")) + logger.Info("") + t.Execute(w, i) +} diff --git a/cmd/warehost-web/main.go b/cmd/warehost-web/main.go new file mode 100644 index 0000000..37b770f --- /dev/null +++ b/cmd/warehost-web/main.go @@ -0,0 +1,54 @@ +package main + +import ( + "flag" + "net" + "net/http" + + "github.com/NYTimes/gziphandler" + "github.com/jinzhu/gorm" + _ "github.com/jinzhu/gorm/dialects/postgres" + + log "dev.sum7.de/sum7/warehost/lib/log" + modul "dev.sum7.de/sum7/warehost/modul/web" + system "dev.sum7.de/sum7/warehost/system" +) + +var ( + configFile string + config *Config + dbconnection *gorm.DB +) + +func main() { + var err error + flag.StringVar(&configFile, "c", "config.yml", "path of configuration file") + flag.Parse() + config = ReadConfigFile(configFile) + log.NewLogger(config.Log.Path) + + // Main Databaseconnection + dbconnection, err = gorm.Open("postgres", config.Database) + if err != nil { + log.Log.Fatal("database connection: ", err) + } + defer dbconnection.Close() + dbconnection.Callback().Create().Remove("gorm:update_time_stamp") + dbconnection.Callback().Update().Remove("gorm:update_time_stamp") + dbconnection.SingularTable(true) + dbconnection.LogMode(config.DatabaseDebug) + + //load system Models to database + system.SyncModels(dbconnection) + modul.SyncModels(dbconnection) + + // http handler + http.Handle("/static/", gziphandler.GzipHandler(http.StripPrefix("/static/", http.HandlerFunc(handlerstatic)))) + http.Handle("/", gziphandler.GzipHandler(http.HandlerFunc(handlerfunc))) + + // Start server + address := net.JoinHostPort(config.Address, config.Port) + log.Log.Info("starting warehost web on ", address) + // TODO bad + log.Log.Fatal(http.ListenAndServe(address, nil)) +} diff --git a/cmd/warehost-web/model.go b/cmd/warehost-web/model.go new file mode 100644 index 0000000..a343d99 --- /dev/null +++ b/cmd/warehost-web/model.go @@ -0,0 +1,11 @@ +package main + +import modul "dev.sum7.de/sum7/warehost/modul/web" + +//TemplateInfo Information send to Template +type TemplateInfo struct { + Host string + URL string + Page *modul.Page + Menu []*modul.Menu +} diff --git a/config.yml.example b/cmd/warehost/config.yml.example similarity index 100% rename from config.yml.example rename to cmd/warehost/config.yml.example diff --git a/main.go b/cmd/warehost/main.go similarity index 96% rename from main.go rename to cmd/warehost/main.go index 4b090a5..6d5ccf1 100644 --- a/main.go +++ b/cmd/warehost/main.go @@ -15,6 +15,7 @@ import ( libconfig "dev.sum7.de/sum7/warehost/config" log "dev.sum7.de/sum7/warehost/lib/log" + modulweb "dev.sum7.de/sum7/warehost/modul/web" "dev.sum7.de/sum7/warehost/system" ) @@ -48,6 +49,7 @@ func main() { dbconnection.LogMode(config.DatabaseDebug) //load system Models to database system.SyncModels(dbconnection) + modulweb.SyncModels(dbconnection) // API routes router := httprouter.New() diff --git a/modul/web/models.go b/modul/web/models.go new file mode 100644 index 0000000..0ab1da9 --- /dev/null +++ b/modul/web/models.go @@ -0,0 +1,76 @@ +package web + +import ( + "database/sql" + "github.com/jinzhu/gorm" + + system "dev.sum7.de/sum7/warehost/system" +) + +// Website struct +type Website struct { + ID int64 + Name string `gorm:"type:varchar(255);column:name" json:"name"` + Domains []Domain `gorm:"foreignkey:Domain" json:"domains"` +} + +// TableName of struct +func (Website) TableName() string { return "web_website" } + +// Domain struct +type Domain struct { + WebsiteID int64 `sql:"type:bigint REFERENCES web_website(id) ON UPDATE CASCADE ON DELETE CASCADE;column:website;primary_key"` + Name string `gorm:"type:varchar(255);unique;column:name" json:"name"` +} + +// TableName of struct +func (Domain) TableName() string { return "web_domain" } + +// Manager struct +type Manager struct { + Login system.Login `gorm:"column:login" json:"login"` + LoginID int64 `sql:"type:bigint REFERENCES login(id) ON UPDATE CASCADE ON DELETE CASCADE;column:login;primary_key"` + WebsiteID int64 `sql:"type:bigint REFERENCES web_website(id) ON UPDATE CASCADE ON DELETE CASCADE;column:website;primary_key"` +} + +// TableName of struct +func (Manager) TableName() string { return "web_manager" } + +// Media struct +type Media struct { + WebsiteID int64 `sql:"type:bigint REFERENCES web_website(id) ON UPDATE CASCADE ON DELETE CASCADE;column:website;primary_key"` + Path string `gorm:"type:varchar(255);column:path;primary_key" json:"path"` +} + +// TableName of struct +func (Media) TableName() string { return "web_media" } + +// Menu struct +type Menu struct { + ID int64 `gorm:"primary_key"` + WebsiteID int64 `sql:"type:bigint REFERENCES web_website(id) ON UPDATE CASCADE ON DELETE CASCADE;column:website"` + Name string `gorm:"type:varchar(255);column:name" json:"name"` + Shorturl string `gorm:"type:varchar(255);column:url" json:"url"` + ParentID sql.NullInt64 `sql:"type:bigint REFERENCES web_menu(id) ON UPDATE SET NULL ON DELETE SET NULL;column:menu"` + Menu []*Menu `gorm:"foreignkey:Menu" json:"menu"` +} + +// TableName of struct +func (Menu) TableName() string { return "web_menu" } + +// Page struct +type Page struct { + ID int64 `gorm:"primary_key"` + WebsiteID int64 `sql:"type:bigint REFERENCES web_website(id) ON UPDATE CASCADE ON DELETE CASCADE;column:website"` + MenuID int64 `sql:"type:bigint REFERENCES web_menu(id) ON UPDATE CASCADE ON DELETE CASCADE;column:menu"` + Title string `gorm:"type:varchar(255);column:title" json:"title"` + Content string `gorm:"type:text;column:content" json:"content"` +} + +// TableName of struct +func (Page) TableName() string { return "web_page" } + +// SyncModels to verify the database schema +func SyncModels(dbconnection *gorm.DB) { + dbconnection.AutoMigrate(&Website{}, &Domain{}, &Manager{}, &Media{}, &Menu{}, &Page{}) +} diff --git a/system/api.go b/system/api.go index 6d51869..4781d70 100644 --- a/system/api.go +++ b/system/api.go @@ -102,8 +102,7 @@ func (api *API) Login(w http.ResponseWriter, r *http.Request, _ httprouter.Param output, _ := libpassword.Validate(login.Password, requestlogin.Password) if output { returndata = true - login.LastLoginAt = time.Now() - api.dbconnection.Save(&login) + api.dbconnection.Model(&login).Update("LastLoginAt", time.Now()) sess.Set("login", login) logger.Info("logged in") } else {