func (publish *Publish) registerWorkerJob() { if w := publish.WorkerScheduler; w != nil { if w.Admin == nil { fmt.Println("Need to add worker to admin first before set worker") return } qorWorkerArgumentResource := w.Admin.NewResource(&QorWorkerArgument{}) qorWorkerArgumentResource.Meta(&admin.Meta{Name: "IDs", Type: "publish_job_argument", Valuer: func(record interface{}, context *qor.Context) interface{} { var values = map[*admin.Resource][][]string{} if workerArgument, ok := record.(*QorWorkerArgument); ok { for _, id := range workerArgument.IDs { if keys := strings.Split(id, "__"); len(keys) >= 2 { name, id := keys[0], keys[1:] recordRes := w.Admin.GetResource(name) values[recordRes] = append(values[recordRes], id) } } } return values }}) w.RegisterJob(&worker.Job{ Name: "Publish", Group: "Publish", Permission: roles.Deny(roles.Read, roles.Anyone), Handler: func(argument interface{}, job worker.QorJobInterface) error { if argu, ok := argument.(*QorWorkerArgument); ok { records := publish.searchWithPublishIDs(publish.DraftDB(), w.Admin, argu.IDs) publish.Logger(&workerJobLogger{job: job}).Publish(records...) } return nil }, Resource: qorWorkerArgumentResource, }) w.RegisterJob(&worker.Job{ Name: "Discard", Group: "Publish", Permission: roles.Deny(roles.Read, roles.Anyone), Handler: func(argument interface{}, job worker.QorJobInterface) error { if argu, ok := argument.(*QorWorkerArgument); ok { records := publish.searchWithPublishIDs(publish.DraftDB(), w.Admin, argu.IDs) publish.Logger(&workerJobLogger{job: job}).Discard(records...) } return nil }, Resource: qorWorkerArgumentResource, }) } }
// ConfigureQorResource used to configure transition for qor admin func (stageChangeLog *StateChangeLog) ConfigureQorResource(res resource.Resourcer) { if res, ok := res.(*admin.Resource); ok { if res.Config.Permission == nil { res.Config.Permission = roles.Deny(roles.Update, roles.Anyone).Deny(roles.Create, roles.Anyone) } else { res.Config.Permission = res.Config.Permission.Deny(roles.Update, roles.Anyone).Deny(roles.Create, roles.Anyone) } } }
// ConfigureQorResource used to configure transition for qor admin func (transition *Transition) ConfigureQorResource(res resource.Resourcer) { if res, ok := res.(*admin.Resource); ok { if res.GetMeta("State") == nil { res.Meta(&admin.Meta{Name: "State", Permission: roles.Deny(roles.Update, roles.Anyone).Deny(roles.Create, roles.Anyone)}) } res.IndexAttrs(res.IndexAttrs(), "-StateChangeLogs") res.ShowAttrs(res.ShowAttrs(), "-StateChangeLogs", false) res.NewAttrs(res.NewAttrs(), "-StateChangeLogs") res.EditAttrs(res.EditAttrs(), "-StateChangeLogs") } }
func SetupAdmin() *admin.Admin { // Setup Database for QOR Admin sorting.RegisterCallbacks(config.DB) validations.RegisterCallbacks(config.DB) media_library.RegisterCallbacks(config.DB) result := admin.New(&qor.Config{DB: config.DB}) result.SetSiteName(config.QOR.SiteName) result.SetAuth(config.Auth) //result.RegisterViewPath("/home/drew/GoWork/src/github.com/8legd/hugocms/vendor/github.com/qor/admin/views") // Add Asset Manager, for rich editor assetManager := result.AddResource(&media_library.AssetManager{}, &admin.Config{Invisible: true}) columnImage := result.NewResource(&models.PageContentColumnImage{}, &admin.Config{Invisible: true}) columnImage.Meta(&admin.Meta{ Name: "Alignment", Type: "select_one", Collection: func(o interface{}, context *qor.Context) [][]string { var result [][]string result = append(result, []string{"media-left media-top", "left top"}) result = append(result, []string{"media-left media-middle", "left middle"}) result = append(result, []string{"media-left media-bottom", "left bottom"}) result = append(result, []string{"media-right media-top", "right top"}) result = append(result, []string{"media-right media-middle", "right middle"}) result = append(result, []string{"media-right media-bottom", "right bottom"}) return result }, }) columnImage.NewAttrs("-ContentColumns") columnImage.EditAttrs("-ContentColumns") columns := result.NewResource(&models.PageContentColumn{}, &admin.Config{Invisible: true}) columns.Meta(&admin.Meta{ Name: "ColumnWidth", Type: "select_one", Collection: func(o interface{}, context *qor.Context) [][]string { var result [][]string result = append(result, []string{"col-md-6", "50% on desktop, 100% on mobile"}) result = append(result, []string{"col-md-12", "100% on desktop, 100% on mobile"}) return result }, }) columns.Meta(&admin.Meta{Name: "ColumnText", Type: "rich_editor", Resource: assetManager}) staticContentSection := &admin.Section{ Title: "Static Content", Rows: [][]string{ {"ColumnText"}, {"ColumnImage"}, }} columns.Meta(&admin.Meta{Name: "ColumnImage", Resource: columnImage}) dynmamicContentSection := &admin.Section{ Title: "Dynamic Content", Rows: [][]string{ {"Video", "Slideshow"}, }} columns.NewAttrs("-Page", "ColumnWidth", "ColumnHeading", staticContentSection, dynmamicContentSection, "ColumnLink") columns.EditAttrs("-Page", "ColumnWidth", "ColumnHeading", staticContentSection, dynmamicContentSection, "ColumnLink") links := result.NewResource(&models.PageLink{}, &admin.Config{Invisible: true}) links.Meta(&admin.Meta{Name: "LinkText", Type: "rich_editor", Resource: assetManager}) links.NewAttrs("-Page") links.EditAttrs("-Page") pages = result.AddResource(&models.Page{}, &admin.Config{Name: "Pages"}) pages.IndexAttrs("Path", "Name") pages.Meta(&admin.Meta{Name: "ContentColumns", Resource: columns}) pages.Meta(&admin.Meta{Name: "Links", Resource: links}) pages.Meta(&admin.Meta{Name: "Path", Type: "select_one", Collection: config.QOR.Paths}) // define scopes for pages for _, path := range config.QOR.Paths { path := path // The anonymous function below captures the variable `path` not its value // So because the range variable is re-assigned a value on each iteration, if we just used it, // the actual value being used would just end up being the same (last value of iteration). // By redeclaring `path` within the range block's scope a new variable is in effect created for each iteration // and that specific variable is used in the anonymous function instead // Another solution would be to pass the range variable into a function as a parameter which then returns the // original function you wanted creating a `closure` around the passed in parameter (you often come accross this in JavaScript) pages.Scope(&admin.Scope{ Name: path, Group: "Path", Handle: func(db *gorm.DB, context *qor.Context) *gorm.DB { return db.Where(models.Page{Path: path}) }, }) } pageSection := &admin.Section{ Title: "Page Setup", Rows: [][]string{ {"Name"}, {"Path", "MenuWeight"}, {"Links"}, }} pages.NewAttrs(pageSection, "SEO", "ContentColumns") pages.EditAttrs(pageSection, "SEO", "ContentColumns") pages.AddValidator(func(record interface{}, metaValues *resource.MetaValues, context *qor.Context) error { if meta := metaValues.Get("Name"); meta != nil { if name := utils.ToString(meta.Value); strings.TrimSpace(name) == "" { return validations.NewError(record, "Name", "Name can not be blank") } } if meta := metaValues.Get("Path"); meta != nil { if name := utils.ToString(meta.Value); strings.TrimSpace(name) == "" { return validations.NewError(record, "Path", "Path can not be blank") } } // TODO make SEO required // if we have content check it is valid if meta := metaValues.Get("ContentColumns"); meta != nil { if metas := meta.MetaValues.Values; len(metas) > 0 { for _, v := range metas { // All image content need alt text and alignment if v.Name == "ImageContent" { if fields := v.MetaValues.Values; len(fields) > 0 { img := false imgAlt := false imgAlign := false for _, f := range fields { if f.Name == "Image" && f.Value != nil { if v, ok := f.Value.([]*multipart.FileHeader); ok { if len(v) > 0 { img = true } } } if f.Name == "Alt" && f.Value != nil { if v, ok := f.Value.([]string); ok { if len(v) > 0 && v[0] != "" { imgAlt = true } } } if f.Name == "Alignment" && f.Value != nil { if v, ok := f.Value.([]string); ok { if len(v) > 0 && v[0] != "" { imgAlign = true } } } } if img && (!imgAlt || !imgAlign) { return validations.NewError(record, "ContentColumns", "All Image Content requires Alt Text and Alignment") } } } } } } return nil }) slideshows = result.AddResource(&models.Slideshow{}, &admin.Config{Name: "Slideshow"}) slideshows.IndexAttrs("Name") videos = result.AddResource(&models.Video{}, &admin.Config{Name: "Videos"}) videos.IndexAttrs("Name") // Add Settings contact := result.NewResource(&models.SettingsContactDetails{}, &admin.Config{Invisible: true}) contact.Meta(&admin.Meta{Name: "OpeningHoursDesktop", Type: "rich_editor", Resource: assetManager}) callToAction := result.NewResource(&models.SettingsCallToAction{}, &admin.Config{Invisible: true}) callToAction.Meta(&admin.Meta{Name: "ActionText", Type: "rich_editor", Resource: assetManager}) settings = result.AddResource(&models.Settings{}, &admin.Config{Singleton: true}) settings.Meta(&admin.Meta{Name: "ContactDetails", Resource: contact}) settings.Meta(&admin.Meta{Name: "CallToAction", Resource: callToAction}) settings.Meta(&admin.Meta{Name: "Footer", Type: "rich_editor", Resource: assetManager}) releases = result.AddResource(&models.Release{}, &admin.Config{ Name: "Releases", Permission: roles.Deny(roles.Delete, roles.Anyone), }) releases.IndexAttrs("ID", "Date", "Comment") releases.NewAttrs("Comment") releases.EditAttrs("") releases.ShowAttrs("ID", "Date", "Comment", "Log") // Add Translations result.AddResource(config.I18n, &admin.Config{}) return result }