Commit b6d0268d authored by Loïck Bonniot's avatar Loïck Bonniot

[p/contract] Add mail management

parent f1a6eb37
Pipeline #226 failed with stage
......@@ -27,6 +27,7 @@ Unit tests:
- "go test -coverprofile authority.part -v dfss/dfssp/authority"
- "go test -coverprofile dfssp_user.part -v dfss/dfssp/user"
- "go test -coverprofile dfssp_contract.part -v dfss/dfssp/contract"
- "go test -coverprofile dfssp_templates.part -v dfss/dfssp/templates"
- "echo 'mode: set' *part > c.out"
- "grep -h -v 'mode: set' *part >> c.out"
- "go tool cover -html=c.out -o coverage.html"
......@@ -45,6 +46,7 @@ ARM tests:
- "go test -cover -short -v dfss/dfssp/authority"
- "go test -cover -short -v dfss/dfssp/user"
- "go test -cover -short -v dfss/dfssp/contract"
- "go test -cover -short -v dfss/dfssp/templates"
Code lint:
stage: test
......
......@@ -7,6 +7,7 @@ import (
"dfss/dfssp/api"
"dfss/dfssp/entities"
"dfss/dfssp/templates"
"dfss/mgdb"
"gopkg.in/mgo.v2/bson"
)
......@@ -25,15 +26,17 @@ func PostRoute(m *mgdb.MongoManager, in *api.PostContractRequest) *api.ErrorCode
return &api.ErrorCode{Code: api.ErrorCode_INTERR, Message: "Database error"}
}
err = addContract(m, in, signers, missingSigners)
contract, err := addContract(m, in, signers, missingSigners)
if err != nil {
log.Println(err)
return &api.ErrorCode{Code: api.ErrorCode_INTERR}
}
if len(missingSigners) > 0 {
sendPendingContractMail(contract, missingSigners)
return &api.ErrorCode{Code: api.ErrorCode_WARNING, Message: "Some users are not ready yet"}
}
sendNewContractMail(contract)
return &api.ErrorCode{Code: api.ErrorCode_SUCCESS}
}
......@@ -84,7 +87,7 @@ func fetchSigners(m *mgdb.MongoManager, signers []string) ([]entities.User, []st
return users, missing, nil
}
func addContract(m *mgdb.MongoManager, in *api.PostContractRequest, signers []entities.User, missingSigners []string) error {
func addContract(m *mgdb.MongoManager, in *api.PostContractRequest, signers []entities.User, missingSigners []string) (*entities.Contract, error) {
contract := entities.NewContract()
for _, s := range signers {
contract.AddSigner(&s.ID, s.Email, s.CertHash)
......@@ -100,5 +103,55 @@ func addContract(m *mgdb.MongoManager, in *api.PostContractRequest, signers []en
contract.File.Hosted = false
_, err := m.Get("contracts").Insert(contract)
return err
return contract, err
}
func sendNewContractMail(c *entities.Contract) {
conn := templates.MailConn()
if conn == nil {
return
}
defer func() { _ = conn.Close() }()
rcpts := make([]string, len(c.Signers))
for i, s := range c.Signers {
rcpts[i] = s.Email
}
content, err := templates.Get("contract", c)
if err != nil {
log.Println(err)
return
}
file, err := GetJSON(c, nil)
if err != nil {
log.Println(err)
return
}
_ = conn.Send(
rcpts,
"[DFSS] You are invited to sign "+c.File.Name,
content,
[]string{"application/json"},
[]string{c.ID.Hex() + ".json"},
[][]byte{file},
)
}
func sendPendingContractMail(c *entities.Contract, rcpts []string) {
conn := templates.MailConn()
if conn == nil {
return
}
defer func() { _ = conn.Close() }()
content, err := templates.Get("invitation", c)
if err != nil {
log.Println(err)
return
}
_ = conn.Send(rcpts, "[DFSS] You are invited to sign "+c.File.Name, content, nil, nil, nil)
}
package templates
const contract = `Dear Sir or Madam,
Someone asked you to sign a contract on the DFSS platform.
Please download the attached file and open it with the DFSS client.
{{template "contractDetails" .}}
{{template "signature"}}
`
const contractDetails = `Signers :
{{range .Signers}} - {{.Email}}
{{end}}
Contract name : {{.File.Name}}
SHA-512 hash : {{.File.Hash}}
Comment : {{.Comment}}
`
package templates
const invitation = `Dear Sir or Madam,
Someone invited you to sign a multiparty contract using the DFSS platform.
Please download the latest version of DFSS an register a new account using
this adress mail in order to sign the contract.
{{template "contractDetails" .}}
{{template "signature"}}
`
package templates
import (
"bytes"
"log"
"os"
"text/template"
"dfss/mails"
)
var tpl *template.Template
var ready bool
const signature = `Yours faithfully,
The DFSS Platform`
// Init compiles templates and panics if encountered an error.
// This method is called automatically one time by `Get`.
func Init() {
tpl = template.Must(template.New("main").Parse("{{define `contract`}}" + contract + "{{end}}"))
_ = template.Must(tpl.Parse("{{define `signature`}}" + signature + "{{end}}"))
_ = template.Must(tpl.Parse("{{define `invitation`}}" + invitation + "{{end}}"))
_ = template.Must(tpl.Parse("{{define `contractDetails`}}" + contractDetails + "{{end}}"))
ready = true
}
// Get computes the asked template with the data provided.
func Get(name string, data interface{}) (string, error) {
if !ready {
Init()
}
b := new(bytes.Buffer)
err := tpl.ExecuteTemplate(b, name, data)
if err != nil {
return "", err
}
return b.String(), nil
}
// MailConn is a helper to return a new mail connection if available.
// The result is null if the mail server is not ready.
// Do not forget to defer the close operation!
func MailConn() *mails.CustomClient {
sender := os.Getenv("DFSS_MAIL_SENDER")
host := os.Getenv("DFSS_MAIL_HOST")
port := os.Getenv("DFSS_MAIL_PORT")
username := os.Getenv("DFSS_MAIL_USERNAME")
password := os.Getenv("DFSS_MAIL_PASSWORD")
if len(sender) == 0 {
return nil
}
c, err := mails.NewCustomClient(sender, host, port, username, password)
if err != nil {
log.Println(err)
return nil
}
return c
}
package templates
import (
"testing"
"dfss/dfssp/entities"
"github.com/bmizerany/assert"
)
func TestInit(t *testing.T) {
Init() // will panic if any error found in templates
}
func TestGet(t *testing.T) {
contract := entities.NewContract()
contract.File.Hash = "hash"
contract.File.Name = "name.pdf"
contract.Comment = "comment"
contract.AddSigner(nil, "mail@example.com", "")
contract.AddSigner(nil, "mail2@example.com", "")
s, err := Get("contract", contract)
expected := `Dear Sir or Madam,
Someone asked you to sign a contract on the DFSS platform.
Please download the attached file and open it with the DFSS client.
Signers :
- mail@example.com
- mail2@example.com
Contract name : name.pdf
SHA-512 hash : hash
Comment : comment
Yours faithfully,
The DFSS Platform
`
assert.Equal(t, nil, err)
assert.Equal(t, expected, s)
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment