Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions broker/Dockerfile.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ broker/**/*_test.go
# Include statemodels
!broker/patron_request/service/statemodels

# Include pull slip templates
!broker/pullslip/service/pull_slip_template.html

# Directory sources are generated inside the build.
directory/api/directory.gen.go
directory/db/db.go
Expand Down
5 changes: 2 additions & 3 deletions broker/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ GIT_COMMIT_DEPS = $(GIT_HEAD_FILE) $(wildcard $(GIT_HEAD_REF_FILE)) $(wildcard $
COVERAGE=coverage.out
STATE_MODELS_JSON=patron_request/service/statemodels/state-models.json
STATE_MODELS_YAML=../misc/state-models.yaml
PULLSLIP_TEMPLATE=pullslip/service/pull_slip_template.html

# SQLC
SQLC ?= $(GO) tool sqlc
Expand Down Expand Up @@ -100,10 +99,10 @@ $(SQL_GEN_OUT): $(SQL_GEN_IN) $(SQLC_CONFIG)
$(COMMIT_ID): $(GIT_COMMIT_DEPS)
commit_id="$$( $(GIT) rev-parse --short HEAD )" && printf '%s' "$$commit_id" > $(COMMIT_ID)

$(BINARY): $(COMMIT_ID) $(SQL_GEN_OUT) $(OAPI_GEN) $(PR_OAPI_GEN) $(PS_OAPI_GEN) $(SCHED_OAPI_GEN) $(BUILD_GOFILES) $(STATE_MODELS_JSON) $(PULLSLIP_TEMPLATE)
$(BINARY): $(COMMIT_ID) $(SQL_GEN_OUT) $(OAPI_GEN) $(PR_OAPI_GEN) $(PS_OAPI_GEN) $(SCHED_OAPI_GEN) $(BUILD_GOFILES) $(STATE_MODELS_JSON)
$(GO) build -v -o $(BINARY) ./$(MAIN_PACKAGE)

archive: $(COMMIT_ID) $(SQL_GEN_OUT) $(OAPI_GEN) $(PR_OAPI_GEN) $(PS_OAPI_GEN) $(SCHED_OAPI_GEN) $(BUILD_GOFILES) $(STATE_MODELS_JSON) $(PULLSLIP_TEMPLATE)
archive: $(COMMIT_ID) $(SQL_GEN_OUT) $(OAPI_GEN) $(PR_OAPI_GEN) $(PS_OAPI_GEN) $(SCHED_OAPI_GEN) $(BUILD_GOFILES) $(STATE_MODELS_JSON)
$(GO) build -v -o archive ./cmd/archive

check: generate
Expand Down
219 changes: 219 additions & 0 deletions broker/email/email.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,23 @@ import (
"encoding/base64"
"errors"
"fmt"
"html/template"
"mime"
"mime/multipart"
"mime/quotedprintable"
"net/smtp"
"net/textproto"
"strings"
text_template "text/template"

pr_db "github.com/indexdata/crosslink/broker/patron_request/db"
"github.com/indexdata/crosslink/iso18626"
"github.com/indexdata/go-utils/utils"
)

const DEFAULT_FOR_NO_VALUE = "n/a"
const DATE_LAYOUT = "2006-01-02"

// Environment variables for SMTP configuration.
var (
SMTP_HOST = utils.GetEnv("SMTP_HOST", "")
Expand Down Expand Up @@ -180,3 +187,215 @@ func joinAddresses(addrs []string) string {
}
return result
}

// Only string fields are allowed
type PullSlipData struct {
Comment thread
JanisSaldabols marked this conversation as resolved.
ReqId string
PickupLocation string
Title string
Author string
DueDate string
ReturnAddress string
BarcodeBase64 string
ServiceType string
ServiceLevel string
SystemIdentifier string
Publisher string
Volume string
Issue string
Pages string
StaffNotes string
CallNumber string
LoanConditions string
PatronName string
PatronSurname string
PatronId string
}

// Only string fields are allowed
type BatchEmailData struct {
FullCount string
ActualCount string
BatchQuery string
}

func GetPullSlipData(pr pr_db.PatronRequest, notes []pr_db.Notification, conditions []pr_db.Notification, barcodeData string) PullSlipData {
Comment thread
JanisSaldabols marked this conversation as resolved.
data := PullSlipData{
ReqId: pr.RequesterReqID.String,
PickupLocation: getPickupLocation(pr),
Title: DEFAULT_FOR_NO_VALUE,
Author: DEFAULT_FOR_NO_VALUE,
DueDate: DEFAULT_FOR_NO_VALUE,
ReturnAddress: DEFAULT_FOR_NO_VALUE,
BarcodeBase64: barcodeData,
ServiceType: DEFAULT_FOR_NO_VALUE,
ServiceLevel: DEFAULT_FOR_NO_VALUE,
SystemIdentifier: DEFAULT_FOR_NO_VALUE,
Publisher: DEFAULT_FOR_NO_VALUE,
Volume: DEFAULT_FOR_NO_VALUE,
Issue: DEFAULT_FOR_NO_VALUE,
Pages: DEFAULT_FOR_NO_VALUE,
StaffNotes: getStaffNotes(notes),
CallNumber: getCallNumber(pr),
LoanConditions: getLoanConditions(conditions),
PatronName: DEFAULT_FOR_NO_VALUE,
PatronSurname: DEFAULT_FOR_NO_VALUE,
PatronId: DEFAULT_FOR_NO_VALUE,
}
if pr.IllRequest.BibliographicInfo.Author != "" {
data.Author = pr.IllRequest.BibliographicInfo.Author
}
if pr.IllRequest.BibliographicInfo.Title != "" {
data.Title = pr.IllRequest.BibliographicInfo.Title
}
if pr.IllRequest.BibliographicInfo.Volume != "" {
data.Volume = pr.IllRequest.BibliographicInfo.Volume
}
if pr.IllRequest.BibliographicInfo.Issue != "" {
data.Issue = pr.IllRequest.BibliographicInfo.Issue
}
if pr.IllRequest.BibliographicInfo.EstimatedNoPages != "" {
data.Pages = pr.IllRequest.BibliographicInfo.EstimatedNoPages
}
if pr.IllRequest.BibliographicInfo.SupplierUniqueRecordId != "" {
data.SystemIdentifier = pr.IllRequest.BibliographicInfo.SupplierUniqueRecordId
}
if pr.IllRequest.PublicationInfo != nil && pr.IllRequest.PublicationInfo.Publisher != "" {
data.Publisher = pr.IllRequest.PublicationInfo.Publisher
}
if pr.IllResponse.StatusInfo.DueDate != nil {
data.DueDate = pr.IllResponse.StatusInfo.DueDate.Format(DATE_LAYOUT)
}
if pr.IllResponse.ReturnInfo != nil && pr.IllResponse.ReturnInfo.PhysicalAddress != nil {
data.ReturnAddress = formatPhysicalAddress(pr.IllResponse.ReturnInfo.PhysicalAddress)
}
if pr.IllRequest.ServiceInfo != nil {
if pr.IllRequest.ServiceInfo.ServiceLevel != nil && pr.IllRequest.ServiceInfo.ServiceLevel.Text != "" {
data.ServiceLevel = pr.IllRequest.ServiceInfo.ServiceLevel.Text
}
if pr.IllRequest.ServiceInfo.ServiceType != "" {
data.ServiceType = string(pr.IllRequest.ServiceInfo.ServiceType)
}
}
if pr.IllRequest.PatronInfo != nil {
if pr.IllRequest.PatronInfo.PatronId != "" {
data.PatronId = pr.IllRequest.PatronInfo.PatronId
}
if pr.IllRequest.PatronInfo.GivenName != "" {
data.PatronName = pr.IllRequest.PatronInfo.GivenName
}
if pr.IllRequest.PatronInfo.Surname != "" {
data.PatronSurname = pr.IllRequest.PatronInfo.Surname
}
}
return data
}

func RenderHtmlTemplate(data any, templateBody string) (string, error) {
tmpl, err := template.New("pull-slip").Parse(templateBody)
Comment thread
JanisSaldabols marked this conversation as resolved.
if err != nil {
return "", err
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, data); err != nil {
return "", err
}
return buf.String(), nil
}

func RenderTextTemplate(data any, templateBody string) (string, error) {
tmpl, err := text_template.New("pull-slip").Parse(templateBody)
if err != nil {
return "", err
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, data); err != nil {
return "", err
}
return buf.String(), nil
}

func getStaffNotes(noteList []pr_db.Notification) string {
noteStrings := []string{}
for _, note := range noteList {
if note.Note.Valid {
noteStrings = append(noteStrings, note.Note.String)
}
}
notes := strings.Join(noteStrings, "\n")
if notes == "" {
return DEFAULT_FOR_NO_VALUE
}
return notes
}

func getLoanConditions(conditionList []pr_db.Notification) string {
conditionStrings := []string{}
for _, note := range conditionList {
if note.Condition.Valid {
conditionStrings = append(conditionStrings, note.Condition.String)
}
}
conditions := strings.Join(conditionStrings, "\n")
if conditions == "" {
return DEFAULT_FOR_NO_VALUE
}
return conditions
}

func getCallNumber(request pr_db.PatronRequest) string {
callNumberStrings := []string{}
for _, item := range request.Items {
if item.CallNumber != nil && *item.CallNumber != "" {
callNumberStrings = append(callNumberStrings, *item.CallNumber)
}
}
callNumber := strings.Join(callNumberStrings, ", ")
if callNumber == "" {
return DEFAULT_FOR_NO_VALUE
}
return callNumber
}

func getPickupLocation(request pr_db.PatronRequest) string {
if len(request.IllRequest.RequestedDeliveryInfo) > 0 && request.IllRequest.RequestedDeliveryInfo[0].Address != nil {
address := *request.IllRequest.RequestedDeliveryInfo[0].Address
if address.PhysicalAddress != nil {
return formatPhysicalAddress(address.PhysicalAddress)
} else if address.ElectronicAddress != nil && address.ElectronicAddress.ElectronicAddressData != "" {
return address.ElectronicAddress.ElectronicAddressData
}
}
return DEFAULT_FOR_NO_VALUE
}

func formatPhysicalAddress(a *iso18626.PhysicalAddress) string {
parts := []string{}
if a.Line1 != "" {
parts = append(parts, a.Line1)
}
if a.Line2 != "" {
parts = append(parts, a.Line2)
}
if a.Locality != "" {
parts = append(parts, a.Locality)
}
if a.PostalCode != "" {
parts = append(parts, a.PostalCode)
}
if a.Region != nil && a.Region.Text != "" {
parts = append(parts, a.Region.Text)
}
if a.Country != nil && a.Country.Text != "" {
parts = append(parts, a.Country.Text)
}
return strings.Join(parts, ", ")
}

func GetBatchEmailData(fullCount int64, actualCount int, batchQuery string) BatchEmailData {
return BatchEmailData{
FullCount: fmt.Sprintf("%d", fullCount),
ActualCount: fmt.Sprintf("%d", actualCount),
BatchQuery: batchQuery,
}
}
Loading