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, &registration.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  }