changeset 5334:45805c454436 extented-report

Load users from database who should receive a report. Generate the report. TODO: Send the report by mail.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Tue, 01 Jun 2021 01:22:10 +0200
parents 6c0f40676984
children dcd5692a2889
files pkg/imports/report.go
diffstat 1 files changed, 108 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/pkg/imports/report.go	Tue Jun 01 00:37:03 2021 +0200
+++ b/pkg/imports/report.go	Tue Jun 01 01:22:10 2021 +0200
@@ -17,9 +17,18 @@
 	"context"
 	"database/sql"
 	"errors"
+	"fmt"
+	"log"
+	"os"
+	"path/filepath"
+	"regexp"
 
 	"gemma.intevation.de/gemma/pkg/common"
+	"gemma.intevation.de/gemma/pkg/config"
 	"gemma.intevation.de/gemma/pkg/models"
+	"gemma.intevation.de/gemma/pkg/xlsx"
+
+	"github.com/360EntSecGroup-Skylar/excelize/v2"
 )
 
 type Report struct {
@@ -69,6 +78,57 @@
 	return nil
 }
 
+func (r *Report) loadTemplate() (*excelize.File, *xlsx.Action, error) {
+	path := config.ReportPath()
+	if path == "" {
+		return nil, nil, errors.New("no report dir configured")
+	}
+
+	if stat, err := os.Stat(path); err != nil {
+		if os.IsNotExist(err) {
+			return nil, nil, fmt.Errorf("report dir '%s' does not exists", path)
+		}
+		return nil, nil, err
+	} else if !stat.Mode().IsDir() {
+		return nil, nil, fmt.Errorf("report dir '%s' is not a directory", path)
+	}
+
+	// TODO: Prevent this earlier.
+	if match, _ := regexp.MatchString(`^[a-zA-Z0-9_]+$`, r.Name); !match {
+		return nil, nil, errors.New("invalid report name")
+	}
+
+	xlsxFilename := filepath.Join(path, r.Name+".xlsx")
+	yamlFilename := filepath.Join(path, r.Name+".yaml")
+
+	for _, check := range []string{xlsxFilename, yamlFilename} {
+		if _, err := os.Stat(check); err != nil {
+			if os.IsNotExist(err) {
+				return nil, nil, fmt.Errorf("'%s' does not exists", check)
+			}
+			return nil, nil, err
+		}
+	}
+
+	template, err := excelize.OpenFile(xlsxFilename)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	action, err := xlsx.ActionFromFile(yamlFilename)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	return template, action, nil
+}
+
+const selectReportUsersSQL = `
+SELECT username, email_address
+FROM users.list_users
+WHERE report_reciever
+ORDER BY country, username`
+
 func (r *Report) Do(
 	ctx context.Context,
 	importID int64,
@@ -76,7 +136,54 @@
 	feedback Feedback,
 ) (interface{}, error) {
 
-	// TODO: Implement me!
+	template, action, err := r.loadTemplate()
+	if err != nil {
+		return nil, err
+	}
+
+	tx, err := conn.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
+	if err != nil {
+		return nil, err
+	}
+	defer tx.Rollback()
+
+	type user struct {
+		name  string
+		email string
+	}
+
+	var users []user
+
+	if err := func() error {
+		rows, err := tx.QueryContext(ctx, selectReportUsersSQL)
+		if err != nil {
+			return err
+		}
+		defer rows.Close()
+
+		for rows.Next() {
+			var u user
+			if err := rows.Scan(&u.name, &u.email); err != nil {
+				return err
+			}
+			users = append(users, u)
+		}
+		return rows.Err()
+	}(); err != nil {
+		return nil, err
+	}
+
+	if len(users) == 0 {
+		feedback.Warn("No users found to send reports to.")
+		return nil, nil
+	}
+
+	if err := action.Execute(ctx, tx, template); err != nil {
+		log.Printf("error: %v\n", err)
+		return nil, fmt.Errorf("Generating report failed: %v", err)
+	}
+
+	// TODO: Send report via email to users.
 
 	return nil, nil
 }