github.com/cs3org/reva/v2@v2.27.7/pkg/siteacc/email/email.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 email
    20  
    21  import (
    22  	"bytes"
    23  	"strings"
    24  	"text/template"
    25  
    26  	"github.com/cs3org/reva/v2/pkg/siteacc/config"
    27  	"github.com/cs3org/reva/v2/pkg/siteacc/data"
    28  	"github.com/cs3org/reva/v2/pkg/smtpclient"
    29  	"github.com/pkg/errors"
    30  )
    31  
    32  type emailData struct {
    33  	Account *data.Account
    34  
    35  	AccountsAddress string
    36  	GOCDBAddress    string
    37  
    38  	Params map[string]string
    39  }
    40  
    41  // SendFunction is the definition of email send functions.
    42  type SendFunction = func(*data.Account, []string, map[string]string, config.Configuration) error
    43  
    44  func getEmailData(account *data.Account, conf config.Configuration, params map[string]string) *emailData {
    45  	return &emailData{
    46  		Account:         account,
    47  		AccountsAddress: conf.Webserver.URL,
    48  		GOCDBAddress:    conf.GOCDB.URL,
    49  		Params:          params,
    50  	}
    51  }
    52  
    53  // SendAccountCreated sends an email about account creation.
    54  func SendAccountCreated(account *data.Account, recipients []string, params map[string]string, conf config.Configuration) error {
    55  	return send(recipients, "ScienceMesh: Site Administrator Account created", accountCreatedTemplate, getEmailData(account, conf, params), conf.Email.SMTP)
    56  }
    57  
    58  // SendSiteAccessGranted sends an email about granted Site access.
    59  func SendSiteAccessGranted(account *data.Account, recipients []string, params map[string]string, conf config.Configuration) error {
    60  	return send(recipients, "ScienceMesh: Site access granted", siteAccessGrantedTemplate, getEmailData(account, conf, params), conf.Email.SMTP)
    61  }
    62  
    63  // SendGOCDBAccessGranted sends an email about granted GOCDB access.
    64  func SendGOCDBAccessGranted(account *data.Account, recipients []string, params map[string]string, conf config.Configuration) error {
    65  	return send(recipients, "ScienceMesh: GOCDB access granted", gocdbAccessGrantedTemplate, getEmailData(account, conf, params), conf.Email.SMTP)
    66  }
    67  
    68  // SendPasswordReset sends an email containing the user's new password.
    69  func SendPasswordReset(account *data.Account, recipients []string, params map[string]string, conf config.Configuration) error {
    70  	return send(recipients, "ScienceMesh: Password reset", passwordResetTemplate, getEmailData(account, conf, params), conf.Email.SMTP)
    71  }
    72  
    73  // SendContactForm sends a generic contact form to the ScienceMesh admins.
    74  func SendContactForm(account *data.Account, recipients []string, params map[string]string, conf config.Configuration) error {
    75  	return send(recipients, "ScienceMesh: Contact form", contactFormTemplate, getEmailData(account, conf, params), conf.Email.SMTP)
    76  }
    77  
    78  // SendAlertNotification sends an alert via email.
    79  func SendAlertNotification(account *data.Account, recipients []string, params map[string]string, conf config.Configuration) error {
    80  	subject := params["Summary"]
    81  	tpl := alertFiringNotificationTemplate
    82  	if strings.EqualFold(params["Status"], "resolved") {
    83  		tpl = alertResolvedNotificationTemplate
    84  		subject += " [RESOLVED]"
    85  	}
    86  	return send(recipients, "ScienceMesh Alert: "+subject, tpl, getEmailData(account, conf, params), conf.Email.SMTP)
    87  }
    88  
    89  func send(recipients []string, subject string, bodyTemplate string, data interface{}, smtp *smtpclient.SMTPCredentials) error {
    90  	// Do not fail if no SMTP client or recipient is given
    91  	if smtp == nil {
    92  		return nil
    93  	}
    94  
    95  	tpl := template.New("email")
    96  	prepareEmailTemplate(tpl)
    97  
    98  	if _, err := tpl.Parse(bodyTemplate); err != nil {
    99  		return errors.Wrap(err, "error while parsing email template")
   100  	}
   101  
   102  	var body bytes.Buffer
   103  	if err := tpl.Execute(&body, data); err != nil {
   104  		return errors.Wrap(err, "error while executing email template")
   105  	}
   106  
   107  	for _, recipient := range recipients {
   108  		if len(recipient) == 0 {
   109  			continue
   110  		}
   111  
   112  		// Send the mail w/o blocking the main thread
   113  		go func(recipient string) {
   114  			_ = smtp.SendMail(recipient, subject, body.String())
   115  		}(recipient)
   116  	}
   117  
   118  	return nil
   119  }
   120  
   121  func prepareEmailTemplate(tpl *template.Template) {
   122  	// Add some custom helper functions to the template
   123  	tpl.Funcs(template.FuncMap{
   124  		"indent": func(n int, s string) string {
   125  			lines := make([]string, 0, 10)
   126  			for _, line := range strings.Split(s, "\n") {
   127  				line = strings.TrimSpace(line)
   128  				line = strings.Repeat(" ", n) + line
   129  				lines = append(lines, line)
   130  			}
   131  			return strings.Join(lines, "\n")
   132  		},
   133  	})
   134  }