github.com/cs3org/reva/v2@v2.27.7/pkg/siteacc/html/panel.go (about) 1 // Copyright 2018-2020 CERN 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 package html 20 21 import ( 22 "html/template" 23 "net/http" 24 "strings" 25 26 "github.com/cs3org/reva/v2/pkg/siteacc/config" 27 "github.com/cs3org/reva/v2/pkg/siteacc/data" 28 "github.com/pkg/errors" 29 "github.com/rs/zerolog" 30 ) 31 32 // TemplateID is the type for template identifiers. 33 type TemplateID = string 34 35 // Panel provides basic HTML panel functionality. 36 type Panel struct { 37 conf *config.Configuration 38 log *zerolog.Logger 39 40 name string 41 42 provider PanelProvider 43 44 templates map[TemplateID]*template.Template 45 } 46 47 const ( 48 pathParameterName = "path" 49 ) 50 51 func (panel *Panel) initialize(name string, provider PanelProvider, conf *config.Configuration, log *zerolog.Logger) error { 52 if name == "" { 53 return errors.Errorf("no name provided") 54 } 55 panel.name = name 56 57 if conf == nil { 58 return errors.Errorf("no configuration provided") 59 } 60 panel.conf = conf 61 62 if log == nil { 63 return errors.Errorf("no logger provided") 64 } 65 panel.log = log 66 67 if provider == nil { 68 return errors.Errorf("no panel provider provided") 69 } 70 panel.provider = provider 71 72 // Create space for the panel templates 73 panel.templates = make(map[string]*template.Template, 5) 74 75 return nil 76 } 77 78 func (panel *Panel) compile(provider ContentProvider) (string, error) { 79 content := panelTemplate 80 81 // Replace placeholders by the values provided by the content provider 82 content = strings.ReplaceAll(content, "$(TITLE)", provider.GetTitle()) 83 content = strings.ReplaceAll(content, "$(CAPTION)", provider.GetCaption()) 84 85 content = strings.ReplaceAll(content, "$(CONTENT_JAVASCRIPT)", provider.GetContentJavaScript()) 86 content = strings.ReplaceAll(content, "$(CONTENT_STYLESHEET)", provider.GetContentStyleSheet()) 87 content = strings.ReplaceAll(content, "$(CONTENT_BODY)", provider.GetContentBody()) 88 89 return content, nil 90 } 91 92 // AddTemplate adds and compiles a new template. 93 func (panel *Panel) AddTemplate(name TemplateID, provider ContentProvider) error { 94 name = panel.getFullTemplateName(name) 95 96 if provider == nil { 97 return errors.Errorf("no content provider provided") 98 } 99 100 content, err := panel.compile(provider) 101 if err != nil { 102 return errors.Wrapf(err, "error while compiling panel template %v", name) 103 } 104 105 tpl := template.New(name) 106 panel.prepareTemplate(tpl) 107 108 if _, err := tpl.Parse(content); err != nil { 109 return errors.Wrapf(err, "error while parsing panel template %v", name) 110 } 111 panel.templates[name] = tpl 112 113 return nil 114 } 115 116 // Execute generates the HTTP output of the panel and writes it to the response writer. 117 func (panel *Panel) Execute(w http.ResponseWriter, r *http.Request, session *Session, dataProvider PanelDataProvider) error { 118 // Get the path query parameter; the panel provider may use this to determine the template to use 119 path := r.URL.Query().Get(pathParameterName) 120 121 actTpl := panel.provider.GetActiveTemplate(session, path) 122 tplName := panel.getFullTemplateName(actTpl) 123 tpl, ok := panel.templates[tplName] 124 if !ok { 125 return errors.Errorf("template %v not found", tplName) 126 } 127 128 // If a data provider is specified, use it to get additional template data 129 var data interface{} 130 if dataProvider != nil { 131 data = dataProvider(session) 132 } 133 134 // Perform the pre-execution phase in which the panel provider can intercept the actual execution 135 if state, err := panel.provider.PreExecute(session, actTpl, w, r); err == nil { 136 if !state { 137 return nil 138 } 139 } else { 140 return errors.Wrapf(err, "pre-execution of template %v failed", tplName) 141 } 142 143 return tpl.Execute(w, data) 144 } 145 146 func (panel *Panel) prepareTemplate(tpl *template.Template) { 147 // Add some custom helper functions to the template 148 tpl.Funcs(template.FuncMap{ 149 "getServerAddress": func() string { 150 return strings.TrimRight(panel.conf.Webserver.URL, "/") 151 }, 152 "getSiteName": func(siteID string, fullName bool) string { 153 siteName, _ := data.QuerySiteName(siteID, fullName, panel.conf.Mentix.URL, panel.conf.Mentix.DataEndpoint) 154 return siteName 155 }, 156 }) 157 } 158 159 func (panel *Panel) getFullTemplateName(name string) string { 160 return panel.name + "-" + name 161 } 162 163 // NewPanel creates a new panel. 164 func NewPanel(name string, provider PanelProvider, conf *config.Configuration, log *zerolog.Logger) (*Panel, error) { 165 panel := &Panel{} 166 if err := panel.initialize(name, provider, conf, log); err != nil { 167 return nil, errors.Wrap(err, "unable to initialize the panel") 168 } 169 return panel, nil 170 }