view pkg/controllers/report.go @ 5711:2dd155cc95ec revive-cleanup

Fix all revive issue (w/o machine generated stuff).
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Tue, 20 Feb 2024 22:22:57 +0100
parents 847de131893a
children
line wrap: on
line source

// This is Free Software under GNU Affero General Public License v >= 3.0
// without warranty, see README.md and license for details.
//
// SPDX-License-Identifier: AGPL-3.0-or-later
// License-Filename: LICENSES/AGPL-3.0.txt
//
// Copyright (C) 2021 by via donau
//   – Österreichische Wasserstraßen-Gesellschaft mbH
// Software engineering by Intevation GmbH
//
// Author(s):
//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>

package controllers

import (
	"database/sql"
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"gemma.intevation.de/gemma/pkg/config"
	"gemma.intevation.de/gemma/pkg/xlsx"

	"gemma.intevation.de/gemma/pkg/log"
	mw "gemma.intevation.de/gemma/pkg/middleware"

	"github.com/gorilla/mux"
	"github.com/xuri/excelize/v2"
)

func listReports(*http.Request) (jr mw.JSONResult, err error) {
	path := config.ReportPath()
	if path == "" {
		err = mw.JSONError{
			Code:    http.StatusNotFound,
			Message: http.StatusText(http.StatusNotFound),
		}
		return
	}

	// This would be easier with Go 1.16+.

	dir, err := os.Open(path)
	if err != nil {
		log.Errorf("%v\n", err)
		err = mw.JSONError{
			Code:    http.StatusInternalServerError,
			Message: "Listing report templates failed.",
		}
		return
	}
	defer dir.Close()
	files, err := dir.Readdirnames(-1)
	if err != nil {
		log.Errorf("%v\n", err)
		err = mw.JSONError{
			Code:    http.StatusInternalServerError,
			Message: "Listing report templates failed.",
		}
		return
	}

	pairs := map[string]int{}

all:
	for _, file := range files {
		var mask int
		switch {
		case strings.HasSuffix(file, ".xlsx"):
			mask = 1
		case strings.HasSuffix(file, ".yaml"):
			mask = 2
		default:
			continue all
		}
		basename := filepath.Base(file)
		name := strings.TrimSuffix(basename, filepath.Ext(basename))
		pairs[name] |= mask
	}

	var reports []string
	for name, mask := range pairs {
		if mask == 3 {
			reports = append(reports, name)
		}
	}
	sort.Strings(reports)

	out := struct {
		Reports []string `json:"reports"`
	}{
		Reports: reports,
	}
	jr = mw.JSONResult{Result: out}
	return
}

func report(rw http.ResponseWriter, req *http.Request) {

	path := config.ReportPath()
	if path == "" {
		http.NotFound(rw, req)
		return
	}

	if stat, err := os.Stat(path); err != nil {
		if os.IsNotExist(err) {
			log.Errorf("report dir '%s' does not exists.\n", path)
			http.NotFound(rw, req)
		} else {
			log.Errorf("%v\n", err)
			http.Error(rw, "Error: "+err.Error(), http.StatusInternalServerError)
		}
		return
	} else if !stat.Mode().IsDir() {
		log.Errorf("report dir '%s' is not a directory.\n", path)
		http.NotFound(rw, req)
		return
	}

	vars := mux.Vars(req)
	name := vars["name"]

	xlsxFilename := filepath.Join(path, name+".xlsx")
	yamlFilename := filepath.Join(path, name+".yaml")

	for _, check := range []string{xlsxFilename, yamlFilename} {
		if _, err := os.Stat(check); err != nil {
			if os.IsNotExist(err) {
				http.NotFound(rw, req)
			} else {
				log.Errorf("%v\n", err)
				http.Error(rw, "Error: "+err.Error(), http.StatusInternalServerError)
			}
			return
		}
	}

	template, err := excelize.OpenFile(xlsxFilename)
	if err != nil {
		log.Errorf("%v\n", err)
		http.Error(rw, "Error: "+err.Error(), http.StatusInternalServerError)
		return
	}

	action, err := xlsx.ActionFromFile(yamlFilename)
	if err != nil {
		http.Error(rw, "Error: "+err.Error(), http.StatusInternalServerError)
		log.Errorf("%v\n", err)
		return
	}

	ctx := req.Context()
	conn := mw.GetDBConn(req)

	tx, err := conn.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
	if err != nil {
		http.Error(rw, "Error: "+err.Error(), http.StatusInternalServerError)
		log.Errorf("%v\n", err)
		return
	}
	defer tx.Rollback()

	if err := action.Execute(ctx, tx, template); err != nil {
		log.Errorf("%v\n", err)
		http.Error(rw, "Error: "+err.Error(), http.StatusInternalServerError)
		return
	}
	rw.Header().Set(
		"Content-Disposition",
		fmt.Sprintf("attachment; filename=%s.xlsx", name))
	rw.Header().Set(
		"Content-Type",
		"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")

	if _, err := template.WriteTo(rw); err != nil {
		log.Errorf("%v\n", err)
	}
}