github.com/kotovmak/go-admin@v1.1.1/plugins/admin/controller/common.go (about) 1 package controller 2 3 import ( 4 "bytes" 5 template2 "html/template" 6 "net/http" 7 "regexp" 8 "strings" 9 "sync" 10 11 "github.com/kotovmak/go-admin/template/types/action" 12 13 "github.com/kotovmak/go-admin/context" 14 "github.com/kotovmak/go-admin/modules/auth" 15 c "github.com/kotovmak/go-admin/modules/config" 16 "github.com/kotovmak/go-admin/modules/db" 17 "github.com/kotovmak/go-admin/modules/language" 18 "github.com/kotovmak/go-admin/modules/menu" 19 "github.com/kotovmak/go-admin/modules/service" 20 "github.com/kotovmak/go-admin/plugins/admin/models" 21 "github.com/kotovmak/go-admin/plugins/admin/modules/constant" 22 "github.com/kotovmak/go-admin/plugins/admin/modules/form" 23 "github.com/kotovmak/go-admin/plugins/admin/modules/table" 24 "github.com/kotovmak/go-admin/template" 25 "github.com/kotovmak/go-admin/template/icon" 26 "github.com/kotovmak/go-admin/template/types" 27 ) 28 29 type Handler struct { 30 config *c.Config 31 captchaConfig map[string]string 32 services service.List 33 conn db.Connection 34 routes context.RouterMap 35 generators table.GeneratorList 36 operations []context.Node 37 navButtons *types.Buttons 38 operationLock sync.Mutex 39 } 40 41 func New(cfg ...Config) *Handler { 42 if len(cfg) == 0 { 43 return &Handler{ 44 operations: make([]context.Node, 0), 45 navButtons: new(types.Buttons), 46 } 47 } 48 return &Handler{ 49 config: cfg[0].Config, 50 services: cfg[0].Services, 51 conn: cfg[0].Connection, 52 generators: cfg[0].Generators, 53 operations: make([]context.Node, 0), 54 navButtons: new(types.Buttons), 55 } 56 } 57 58 type Config struct { 59 Config *c.Config 60 Services service.List 61 Connection db.Connection 62 Generators table.GeneratorList 63 } 64 65 func (h *Handler) UpdateCfg(cfg Config) { 66 h.config = cfg.Config 67 h.services = cfg.Services 68 h.conn = cfg.Connection 69 h.generators = cfg.Generators 70 } 71 72 func (h *Handler) SetCaptcha(captcha map[string]string) { 73 h.captchaConfig = captcha 74 } 75 76 func (h *Handler) SetRoutes(r context.RouterMap) { 77 h.routes = r 78 } 79 80 func (h *Handler) table(prefix string, ctx *context.Context) table.Table { 81 t := h.generators[prefix](ctx) 82 authHandler := auth.Middleware(db.GetConnection(h.services)) 83 for _, cb := range t.GetInfo().Callbacks { 84 if cb.Value[constant.ContextNodeNeedAuth] == 1 { 85 h.AddOperation(context.Node{ 86 Path: cb.Path, 87 Method: cb.Method, 88 Handlers: append([]context.Handler{authHandler}, cb.Handlers...), 89 }) 90 } else { 91 h.AddOperation(context.Node{Path: cb.Path, Method: cb.Method, Handlers: cb.Handlers}) 92 } 93 } 94 for _, cb := range t.GetForm().Callbacks { 95 if cb.Value[constant.ContextNodeNeedAuth] == 1 { 96 h.AddOperation(context.Node{ 97 Path: cb.Path, 98 Method: cb.Method, 99 Handlers: append([]context.Handler{authHandler}, cb.Handlers...), 100 }) 101 } else { 102 h.AddOperation(context.Node{Path: cb.Path, Method: cb.Method, Handlers: cb.Handlers}) 103 } 104 } 105 return t 106 } 107 108 func (h *Handler) route(name string) context.Router { 109 return h.routes.Get(name) 110 } 111 112 func (h *Handler) routePath(name string, value ...string) string { 113 return h.config.Prefix() + h.routes.Get(name).GetURL(value...) 114 } 115 116 func (h *Handler) routePathWithPrefix(name string, prefix string) string { 117 return h.routePath(name, "prefix", prefix) 118 } 119 120 func (h *Handler) AddOperation(nodes ...context.Node) { 121 h.operationLock.Lock() 122 defer h.operationLock.Unlock() 123 // TODO: 避免重复增加,第一次加入后,后面大部分会存在重复情况,以下循环可以优化 124 addNodes := make([]context.Node, 0) 125 for _, node := range nodes { 126 if h.searchOperation(node.Path, node.Method) { 127 continue 128 } 129 addNodes = append(addNodes, node) 130 } 131 h.operations = append(h.operations, addNodes...) 132 } 133 134 func (h *Handler) AddNavButton(btns *types.Buttons) { 135 h.navButtons = btns 136 for _, btn := range *btns { 137 h.AddOperation(btn.GetAction().GetCallbacks()) 138 } 139 } 140 141 func (h *Handler) searchOperation(path, method string) bool { 142 for _, node := range h.operations { 143 if node.Path == path && node.Method == method { 144 return true 145 } 146 } 147 return false 148 } 149 150 func (h *Handler) OperationHandler(path string, ctx *context.Context) bool { 151 for _, node := range h.operations { 152 if node.Path == path { 153 for _, handler := range node.Handlers { 154 handler(ctx) 155 } 156 return true 157 } 158 } 159 return false 160 } 161 162 func (h *Handler) HTML(ctx *context.Context, user models.UserModel, panel types.Panel, 163 options ...template.ExecuteOptions) { 164 buf := h.Execute(ctx, user, panel, "", options...) 165 ctx.HTML(http.StatusOK, buf.String()) 166 } 167 168 func (h *Handler) HTMLPlug(ctx *context.Context, user models.UserModel, panel types.Panel, plugName string, 169 options ...template.ExecuteOptions) { 170 var btns types.Buttons 171 if plugName == "" { 172 btns = (*h.navButtons).CheckPermission(user) 173 } else { 174 btns = (*h.navButtons).Copy(). 175 RemoveToolNavButton(). 176 RemoveSiteNavButton(). 177 RemoveInfoNavButton(). 178 Add(types.GetDropDownButton("", icon.Gear, []*types.NavDropDownItemButton{ 179 types.GetDropDownItemButton(language.GetFromHtml("plugin setting"), 180 action.Jump(h.config.Url("/info/plugin_"+plugName+"/edit"))), 181 types.GetDropDownItemButton(language.GetFromHtml("menus manage"), 182 action.Jump(h.config.Url("/menu?__plugin_name="+plugName))), 183 })). 184 CheckPermission(user) 185 } 186 buf := h.ExecuteWithBtns(ctx, user, panel, plugName, btns, options...) 187 ctx.HTML(http.StatusOK, buf.String()) 188 } 189 190 func (h *Handler) ExecuteWithBtns(ctx *context.Context, user models.UserModel, panel types.Panel, plugName string, btns types.Buttons, 191 options ...template.ExecuteOptions) *bytes.Buffer { 192 193 tmpl, tmplName := aTemplate().GetTemplate(isPjax(ctx)) 194 option := template.GetExecuteOptions(options) 195 196 return template.Execute(&template.ExecuteParam{ 197 User: user, 198 TmplName: tmplName, 199 Tmpl: tmpl, 200 Panel: panel, 201 Config: h.config, 202 Menu: menu.GetGlobalMenu(user, h.conn, ctx.Lang(), plugName).SetActiveClass(h.config.URLRemovePrefix(ctx.Path())), 203 Animation: option.Animation, 204 Buttons: btns, 205 Iframe: ctx.IsIframe(), 206 IsPjax: isPjax(ctx), 207 NoCompress: option.NoCompress, 208 }) 209 } 210 211 func (h *Handler) Execute(ctx *context.Context, user models.UserModel, panel types.Panel, plugName string, 212 options ...template.ExecuteOptions) *bytes.Buffer { 213 214 tmpl, tmplName := aTemplate().GetTemplate(isPjax(ctx)) 215 option := template.GetExecuteOptions(options) 216 217 return template.Execute(&template.ExecuteParam{ 218 User: user, 219 TmplName: tmplName, 220 Tmpl: tmpl, 221 Panel: panel, 222 Config: h.config, 223 Menu: menu.GetGlobalMenu(user, h.conn, ctx.Lang(), plugName).SetActiveClass(h.config.URLRemovePrefix(ctx.Path())), 224 Animation: option.Animation, 225 Buttons: (*h.navButtons).CheckPermission(user), 226 Iframe: ctx.IsIframe(), 227 IsPjax: isPjax(ctx), 228 NoCompress: option.NoCompress, 229 }) 230 } 231 232 func isInfoUrl(s string) bool { 233 reg, _ := regexp.Compile("(.*?)info/(.*?)$") 234 sub := reg.FindStringSubmatch(s) 235 return len(sub) > 2 && !strings.Contains(sub[2], "/") 236 } 237 238 func isNewUrl(s string, p string) bool { 239 reg, _ := regexp.Compile("(.*?)info/" + p + "/new") 240 return reg.MatchString(s) 241 } 242 243 func isEditUrl(s string, p string) bool { 244 reg, _ := regexp.Compile("(.*?)info/" + p + "/edit") 245 return reg.MatchString(s) 246 } 247 248 func (h *Handler) authSrv() *auth.TokenService { 249 return auth.GetTokenService(h.services.Get(auth.TokenServiceKey)) 250 } 251 252 func aAlert() types.AlertAttribute { 253 return aTemplate().Alert() 254 } 255 256 func aForm() types.FormAttribute { 257 return aTemplate().Form() 258 } 259 260 func aRow() types.RowAttribute { 261 return aTemplate().Row() 262 } 263 264 func aCol() types.ColAttribute { 265 return aTemplate().Col() 266 } 267 268 func aImage() types.ImgAttribute { 269 return aTemplate().Image() 270 } 271 272 func aButton() types.ButtonAttribute { 273 return aTemplate().Button() 274 } 275 276 func aTree() types.TreeAttribute { 277 return aTemplate().Tree() 278 } 279 280 func aTable() types.TableAttribute { 281 return aTemplate().Table() 282 } 283 284 func aDataTable() types.DataTableAttribute { 285 return aTemplate().DataTable() 286 } 287 288 func aBox() types.BoxAttribute { 289 return aTemplate().Box() 290 } 291 292 func aTab() types.TabsAttribute { 293 return aTemplate().Tabs() 294 } 295 296 func aTemplate() template.Template { 297 return template.Get(c.GetTheme()) 298 } 299 300 func isPjax(ctx *context.Context) bool { 301 return ctx.IsPjax() 302 } 303 304 func formFooter(page string, isHideEdit, isHideNew, isHideReset bool, btnWord template2.HTML) template2.HTML { 305 col1 := aCol().SetSize(types.SizeMD(2)).GetContent() 306 307 var ( 308 checkBoxs template2.HTML 309 checkBoxJS template2.HTML 310 311 editCheckBox = template.HTML(` 312 <label class="pull-right" style="margin: 5px 10px 0 0;"> 313 <input type="checkbox" class="continue_edit" style="position: absolute; opacity: 0;"> ` + language.Get("continue editing") + ` 314 </label>`) 315 newCheckBox = template.HTML(` 316 <label class="pull-right" style="margin: 5px 10px 0 0;"> 317 <input type="checkbox" class="continue_new" style="position: absolute; opacity: 0;"> ` + language.Get("continue creating") + ` 318 </label>`) 319 320 editWithNewCheckBoxJs = template.HTML(`$('.continue_edit').iCheck({checkboxClass: 'icheckbox_minimal-blue'}).on('ifChanged', function (event) { 321 if (this.checked) { 322 $('.continue_new').iCheck('uncheck'); 323 $('input[name="` + form.PreviousKey + `"]').val(location.href) 324 } else { 325 $('input[name="` + form.PreviousKey + `"]').val(previous_url_goadmin) 326 } 327 }); `) 328 329 newWithEditCheckBoxJs = template.HTML(`$('.continue_new').iCheck({checkboxClass: 'icheckbox_minimal-blue'}).on('ifChanged', function (event) { 330 if (this.checked) { 331 $('.continue_edit').iCheck('uncheck'); 332 $('input[name="` + form.PreviousKey + `"]').val(location.href.replace('/edit', '/new')) 333 } else { 334 $('input[name="` + form.PreviousKey + `"]').val(previous_url_goadmin) 335 } 336 });`) 337 ) 338 339 if page == "edit" { 340 if isHideNew { 341 newCheckBox = "" 342 newWithEditCheckBoxJs = "" 343 } 344 if isHideEdit { 345 editCheckBox = "" 346 editWithNewCheckBoxJs = "" 347 } 348 checkBoxs = editCheckBox + newCheckBox 349 checkBoxJS = `<script> 350 let previous_url_goadmin = $('input[name="` + form.PreviousKey + `"]').attr("value") 351 ` + editWithNewCheckBoxJs + newWithEditCheckBoxJs + ` 352 </script> 353 ` 354 } else if page == "edit_only" && !isHideEdit { 355 checkBoxs = editCheckBox 356 checkBoxJS = template.HTML(` <script> 357 let previous_url_goadmin = $('input[name="` + form.PreviousKey + `"]').attr("value") 358 $('.continue_edit').iCheck({checkboxClass: 'icheckbox_minimal-blue'}).on('ifChanged', function (event) { 359 if (this.checked) { 360 $('input[name="` + form.PreviousKey + `"]').val(location.href) 361 } else { 362 $('input[name="` + form.PreviousKey + `"]').val(previous_url_goadmin) 363 } 364 }); 365 </script> 366 `) 367 } else if page == "new" && !isHideNew { 368 checkBoxs = newCheckBox 369 checkBoxJS = template.HTML(` <script> 370 let previous_url_goadmin = $('input[name="` + form.PreviousKey + `"]').attr("value") 371 $('.continue_new').iCheck({checkboxClass: 'icheckbox_minimal-blue'}).on('ifChanged', function (event) { 372 if (this.checked) { 373 $('input[name="` + form.PreviousKey + `"]').val(location.href) 374 } else { 375 $('input[name="` + form.PreviousKey + `"]').val(previous_url_goadmin) 376 } 377 }); 378 </script> 379 `) 380 } 381 382 btn1 := aButton(). 383 SetType("submit"). 384 AddClass("submit"). 385 SetContent(btnWord). 386 SetThemePrimary(). 387 SetOrientationRight(). 388 GetContent() 389 btn2 := template.HTML("") 390 if !isHideReset { 391 btn2 = aButton(). 392 SetType("reset"). 393 AddClass("reset"). 394 SetContent(language.GetFromHtml("Reset")). 395 SetThemeWarning(). 396 SetOrientationLeft(). 397 GetContent() 398 } 399 col2 := aCol().SetSize(types.SizeMD(8)). 400 SetContent(btn1 + checkBoxs + btn2 + checkBoxJS).GetContent() 401 return col1 + col2 402 } 403 404 func filterFormFooter(infoUrl string) template2.HTML { 405 col1 := aCol().SetSize(types.SizeMD(2)).GetContent() 406 btn1 := aButton().SetType("submit"). 407 AddClass("submit"). 408 SetContent(icon.Icon(icon.Search, 2) + language.GetFromHtml("search")). 409 SetThemePrimary(). 410 SetSmallSize(). 411 SetOrientationLeft(). 412 SetLoadingText(icon.Icon(icon.Spinner, 1) + language.GetFromHtml("search")). 413 GetContent() 414 btn2 := aButton().SetType("reset"). 415 AddClass("reset"). 416 SetContent(icon.Icon(icon.Undo, 2) + language.GetFromHtml("reset")). 417 SetThemeDefault(). 418 SetOrientationLeft(). 419 SetSmallSize(). 420 SetHref(infoUrl). 421 SetMarginLeft(12). 422 GetContent() 423 col2 := aCol().SetSize(types.SizeMD(8)). 424 SetContent(btn1 + btn2).GetContent() 425 return col1 + col2 426 } 427 428 func formContent(form types.FormAttribute, isTab, iframe, isHideBack bool, header template2.HTML) template2.HTML { 429 if isTab { 430 return form.GetContent() 431 } 432 if iframe { 433 header = "" 434 } else if header == template2.HTML("") { 435 header = form.GetDefaultBoxHeader(isHideBack) 436 } 437 return aBox(). 438 SetHeader(header). 439 WithHeadBorder(). 440 SetStyle(" "). 441 SetIframeStyle(iframe). 442 SetBody(form.GetContent()). 443 GetContent() 444 } 445 446 func detailContent(form types.FormAttribute, editUrl, deleteUrl string, iframe bool) template2.HTML { 447 return aBox(). 448 SetHeader(form.GetDetailBoxHeader(editUrl, deleteUrl)). 449 WithHeadBorder(). 450 SetBody(form.GetContent()). 451 SetIframeStyle(iframe). 452 GetContent() 453 } 454 455 func menuFormContent(form types.FormAttribute) template2.HTML { 456 return aBox(). 457 SetHeader(form.GetBoxHeaderNoButton()). 458 SetStyle(" "). 459 WithHeadBorder(). 460 SetBody(form.GetContent()). 461 GetContent() 462 }