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  }