github.com/cs3org/reva/v2@v2.27.7/pkg/siteacc/account/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 account 20 21 import ( 22 "net/http" 23 "net/url" 24 25 "github.com/cs3org/reva/v2/pkg/siteacc/account/contact" 26 "github.com/cs3org/reva/v2/pkg/siteacc/account/edit" 27 "github.com/cs3org/reva/v2/pkg/siteacc/account/login" 28 "github.com/cs3org/reva/v2/pkg/siteacc/account/manage" 29 "github.com/cs3org/reva/v2/pkg/siteacc/account/registration" 30 "github.com/cs3org/reva/v2/pkg/siteacc/account/settings" 31 "github.com/cs3org/reva/v2/pkg/siteacc/account/site" 32 "github.com/cs3org/reva/v2/pkg/siteacc/config" 33 "github.com/cs3org/reva/v2/pkg/siteacc/data" 34 "github.com/cs3org/reva/v2/pkg/siteacc/html" 35 "github.com/pkg/errors" 36 "github.com/rs/zerolog" 37 "golang.org/x/text/cases" 38 "golang.org/x/text/language" 39 ) 40 41 // Panel represents the account panel. 42 type Panel struct { 43 html.PanelProvider 44 45 conf *config.Configuration 46 47 htmlPanel *html.Panel 48 } 49 50 const ( 51 templateLogin = "login" 52 templateManage = "manage" 53 templateSettings = "settings" 54 templateEdit = "edit" 55 templateSite = "site" 56 templateContact = "contact" 57 templateRegistration = "register" 58 ) 59 60 func (panel *Panel) initialize(conf *config.Configuration, log *zerolog.Logger) error { 61 if conf == nil { 62 return errors.Errorf("no configuration provided") 63 } 64 panel.conf = conf 65 66 // Create the internal HTML panel 67 htmlPanel, err := html.NewPanel("account-panel", panel, conf, log) 68 if err != nil { 69 return errors.Wrap(err, "unable to create the account panel") 70 } 71 panel.htmlPanel = htmlPanel 72 73 // Add all templates 74 if err := panel.htmlPanel.AddTemplate(templateLogin, &login.PanelTemplate{}); err != nil { 75 return errors.Wrap(err, "unable to create the login template") 76 } 77 78 if err := panel.htmlPanel.AddTemplate(templateManage, &manage.PanelTemplate{}); err != nil { 79 return errors.Wrap(err, "unable to create the account management template") 80 } 81 82 if err := panel.htmlPanel.AddTemplate(templateSettings, &settings.PanelTemplate{}); err != nil { 83 return errors.Wrap(err, "unable to create the account settings template") 84 } 85 86 if err := panel.htmlPanel.AddTemplate(templateEdit, &edit.PanelTemplate{}); err != nil { 87 return errors.Wrap(err, "unable to create the account editing template") 88 } 89 90 if err := panel.htmlPanel.AddTemplate(templateSite, &site.PanelTemplate{}); err != nil { 91 return errors.Wrap(err, "unable to create the site template") 92 } 93 94 if err := panel.htmlPanel.AddTemplate(templateContact, &contact.PanelTemplate{}); err != nil { 95 return errors.Wrap(err, "unable to create the contact template") 96 } 97 98 if err := panel.htmlPanel.AddTemplate(templateRegistration, ®istration.PanelTemplate{}); err != nil { 99 return errors.Wrap(err, "unable to create the registration template") 100 } 101 102 return nil 103 } 104 105 // GetActiveTemplate returns the name of the active template. 106 func (panel *Panel) GetActiveTemplate(session *html.Session, path string) string { 107 validPaths := []string{templateLogin, templateManage, templateSettings, templateEdit, templateSite, templateContact, templateRegistration} 108 template := templateLogin 109 110 // Only allow valid template paths; redirect to the login page otherwise 111 for _, valid := range validPaths { 112 if valid == path { 113 template = path 114 break 115 } 116 } 117 118 return template 119 } 120 121 // PreExecute is called before the actual template is being executed. 122 func (panel *Panel) PreExecute(session *html.Session, path string, w http.ResponseWriter, r *http.Request) (html.ExecutionResult, error) { 123 protectedPaths := []string{templateManage, templateSettings, templateEdit, templateSite, templateContact} 124 125 if user := session.LoggedInUser(); user != nil { 126 switch path { 127 case templateSite: 128 // If the logged in user doesn't have site access, redirect him back to the main account page 129 if !user.Account.Data.SiteAccess { 130 return panel.redirect(templateManage, w, r), nil 131 } 132 133 case templateLogin: 134 case templateRegistration: 135 // If a user is logged in and tries to login or register again, redirect to the main account page 136 return panel.redirect(templateManage, w, r), nil 137 } 138 } else { 139 // If no user is logged in, redirect protected paths to the login page 140 for _, protected := range protectedPaths { 141 if protected == path { 142 return panel.redirect(templateLogin, w, r), nil 143 } 144 } 145 } 146 147 return html.ContinueExecution, nil 148 } 149 150 // Execute generates the HTTP output of the form and writes it to the response writer. 151 func (panel *Panel) Execute(w http.ResponseWriter, r *http.Request, session *html.Session) error { 152 dataProvider := func(*html.Session) interface{} { 153 flatValues := make(map[string]string, len(r.URL.Query())) 154 c := cases.Title(language.Und) 155 for k, v := range r.URL.Query() { 156 flatValues[c.String(k)] = v[0] 157 } 158 159 availSites, err := data.QueryAvailableSites(panel.conf.Mentix.URL, panel.conf.Mentix.DataEndpoint) 160 if err != nil { 161 return errors.Wrap(err, "unable to query available sites") 162 } 163 164 type TemplateData struct { 165 Site *data.Site 166 Account *data.Account 167 Params map[string]string 168 169 Titles []string 170 Sites []data.SiteInformation 171 } 172 173 tplData := TemplateData{ 174 Site: nil, 175 Account: nil, 176 Params: flatValues, 177 Titles: []string{"Mr", "Mrs", "Ms", "Prof", "Dr"}, 178 Sites: availSites, 179 } 180 if user := session.LoggedInUser(); user != nil { 181 tplData.Site = panel.cloneUserSite(user.Site) 182 tplData.Account = user.Account 183 } 184 return tplData 185 } 186 return panel.htmlPanel.Execute(w, r, session, dataProvider) 187 } 188 189 func (panel *Panel) redirect(path string, w http.ResponseWriter, r *http.Request) html.ExecutionResult { 190 // Check if the original (full) URI path is stored in the request header; if not, use the request URI to get the path 191 fullPath := r.Header.Get("X-Replaced-Path") 192 if fullPath == "" { 193 uri, _ := url.Parse(r.RequestURI) 194 fullPath = uri.Path 195 } 196 197 // Modify the original request URL by replacing the path parameter 198 newURL, _ := url.Parse(fullPath) 199 params := newURL.Query() 200 params.Del("path") 201 params.Add("path", path) 202 newURL.RawQuery = params.Encode() 203 http.Redirect(w, r, newURL.String(), http.StatusFound) 204 return html.AbortExecution 205 } 206 207 func (panel *Panel) cloneUserSite(site *data.Site) *data.Site { 208 // Clone the user's site and decrypt the credentials for the panel 209 siteClone := site.Clone(true) 210 id, secret, err := site.Config.TestClientCredentials.Get(panel.conf.Security.CredentialsPassphrase) 211 if err == nil { 212 siteClone.Config.TestClientCredentials.ID = id 213 siteClone.Config.TestClientCredentials.Secret = secret 214 } 215 return siteClone 216 } 217 218 // NewPanel creates a new account panel. 219 func NewPanel(conf *config.Configuration, log *zerolog.Logger) (*Panel, error) { 220 form := &Panel{} 221 if err := form.initialize(conf, log); err != nil { 222 return nil, errors.Wrap(err, "unable to initialize the account panel") 223 } 224 return form, nil 225 }