package main import ( "flag" "io" "os" "text/template" "github.com/zitadel/logging" "github.com/zitadel/zitadel/internal/config" ) var ( directory = flag.String("directory", "./", "working directory: asset.yaml must be in this directory, files will be generated into parent directory") assetsDocs = flag.String("assets", "../../../../docs/docs/apis/assets/assets.md", "path where the assets.md will be generated") assetPrefix = flag.String("handler-prefix", "/assets/v1", "prefix of the handler paths") ) func main() { flag.Parse() configFile := *directory + "asset.yaml" authz, err := os.OpenFile(*directory+"../authz.go", os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0755) logging.OnError(err).Fatal("cannot open authz file") router, err := os.OpenFile(*directory+"../router.go", os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0755) logging.OnError(err).Fatal("cannot open router file") docs, err := os.OpenFile(*assetsDocs, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0755) logging.OnError(err).Fatal("cannot open docs file") GenerateAssetHandler(configFile, *assetPrefix, authz, router, docs) } type Method struct { Path string HasDarkMode bool Handlers []Handler } type Handler struct { Name string Comment string Type HandlerType Permission string } func (a Handler) Method() string { if a.Type == MethodTypeUpload { return "POST" } return "GET" } func (a Handler) PathSuffix() string { if a.Type == MethodTypePreview { return "/_preview" } return "" } func (a Handler) MethodReturn() string { if a.Type == MethodTypeUpload { return "Uploader" } if a.Type == MethodTypeDownload { return "Downloader" } if a.Type == MethodTypePreview { return "Downloader" } return "" } func (a Handler) HandlerType() string { if a.Type == MethodTypeUpload { return "UploadHandleFunc" } if a.Type == MethodTypeDownload { return "DownloadHandleFunc" } if a.Type == MethodTypePreview { return "DownloadHandleFunc" } return "" } type HandlerType string const ( MethodTypeUpload = "upload" MethodTypeDownload = "download" MethodTypePreview = "preview" ) type Services map[string]Service type Service struct { Prefix string Methods map[string]Method } func GenerateAssetHandler(configFilePath, handlerPrefix string, authz, router, docs io.Writer) { conf := new(struct { Services Services }) err := config.Read(conf, configFilePath) logging.Log("ASSETS-Dgbn4").OnError(err).Fatal("cannot read config") tmplAuthz, err := template.New("").Parse(authzTmpl) logging.Log("ASSETS-BGbbg").OnError(err).Fatal("cannot parse authz template") tmplRouter, err := template.New("").Parse(routerTmpl) logging.Log("ASSETS-gh4rq").OnError(err).Fatal("cannot parse router template") tmplDocs, err := template.New("").Parse(docsTmpl) logging.Log("ASSETS-FGdgs").OnError(err).Fatal("cannot parse docs template") data := &struct { GoPkgName string Name string Prefix string Services Services }{ GoPkgName: "assets", Name: "AssetsService", Prefix: handlerPrefix, Services: conf.Services, } err = tmplAuthz.Execute(authz, data) logging.Log("ASSETS-BHngj").OnError(err).Fatal("cannot generate authz") err = tmplRouter.Execute(router, data) logging.Log("ASSETS-Bfd41").OnError(err).Fatal("cannot generate router") err = tmplDocs.Execute(docs, data) logging.Log("ASSETS-Bfd41").OnError(err).Fatal("cannot generate docs") } const authzTmpl = `// Code generated by assets generator. DO NOT EDIT. package {{.GoPkgName}} import ( "github.com/zitadel/zitadel/internal/api/authz" ) /** * {{.Name}} */ {{ $prefix := .Prefix }} var {{.Name}}_AuthMethods = authz.MethodMapping { {{ range $service := .Services}} {{ range $method := .Methods}} {{ range $handler := .Handlers}} {{ if $handler.Permission }} "{{$handler.Method}}:{{$prefix}}{{$service.Prefix}}{{$method.Path}}{{$handler.PathSuffix}}": authz.Option{ Permission: "{{$handler.Permission}}", }, {{ if $method.HasDarkMode }} "{{$handler.Method}}:{{$prefix}}{{$service.Prefix}}{{$method.Path}}/dark{{$handler.PathSuffix}}": authz.Option{ Permission: "{{$handler.Permission}}", }, {{end}} {{end}} {{end}} {{end}} {{end}} } ` const routerTmpl = `// Code generated by assets generator. DO NOT EDIT. package {{.GoPkgName}} import ( "github.com/gorilla/mux" http_mw "github.com/zitadel/zitadel/internal/api/http/middleware" "github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/static" ) type {{.Name}} interface { AuthInterceptor() *http_mw.AuthInterceptor Commands() *command.Commands ErrorHandler() ErrorHandler Storage() static.Storage {{ range $service := .Services}} {{ range $methodName, $method := .Methods}} {{ range $handler := .Handlers}} {{$handler.Name}}{{$methodName}}() {{if $handler.MethodReturn}}{{$handler.MethodReturn}}{{end}} {{ if $method.HasDarkMode }} {{$handler.Name}}{{$methodName}}Dark() {{if $handler.MethodReturn}}{{$handler.MethodReturn}}{{end}} {{ end }} {{ end }} {{ end }} {{ end }} } func RegisterRoutes(router *mux.Router, s {{.Name}}) { router.Use(s.AuthInterceptor().Handler) {{ range $service := .Services}} {{ range $methodName, $method := .Methods}} {{ range $handler := .Handlers}} router.Path("{{$service.Prefix}}{{$method.Path}}{{$handler.PathSuffix}}").Methods("{{$handler.Method}}").HandlerFunc({{if $handler.HandlerType}}{{$handler.HandlerType}}(s, {{end}}s.{{$handler.Name}}{{$methodName}}(){{if $handler.HandlerType}}){{end}}) {{ if $method.HasDarkMode }} router.Path("{{$service.Prefix}}{{$method.Path}}/dark{{$handler.PathSuffix}}").Methods("{{$handler.Method}}").HandlerFunc({{if $handler.HandlerType}}{{$handler.HandlerType}}(s, {{end}}s.{{$handler.Name}}{{$methodName}}Dark(){{if $handler.HandlerType}}){{end}}) {{ end }} {{ end }} {{ end }} {{ end }} } ` const docsTmpl = `--- title: zitadel/assets --- ## {{.Name}} {{ range $service := .Services}} {{ range $methodName, $method := .Methods}} {{ range $handler := .Handlers}} ### {{$handler.Name}}{{$methodName}}() > {{$handler.Name}}{{$methodName}}() {{$handler.Method}}: {{$service.Prefix}}{{$method.Path}}{{$handler.PathSuffix}} {{ if $method.HasDarkMode }} ### {{$handler.Name}}{{$methodName}}() > {{$handler.Name}}{{$methodName}}Dark() {{$handler.Method}}: {{$service.Prefix}}{{$method.Path}}/dark{{$handler.PathSuffix}} {{ end }} {{ end }} {{ end }} {{ end }} `