view pkg/controllers/routes.go @ 5380:a4b52a3ae0bd extented-report

Allow dash (`-') in report names.
author wilde@azure1.rgb.intevation.de
date Thu, 24 Jun 2021 16:48:50 +0200
parents cb46f50ba168
children d19fdf3d2099
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) 2018, 2020 by via donau
//   – Österreichische Wasserstraßen-Gesellschaft mbH
// Software engineering by Intevation GmbH
//
// Author(s):
//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
//  * Sascha Wilde <sascha.wilde@intevation.de>

package controllers

import (
	"encoding/json"
	"net/http"
	"net/http/httputil"
	"strings"

	"github.com/gorilla/mux"

	"gemma.intevation.de/gemma/pkg/auth"
	"gemma.intevation.de/gemma/pkg/imports"
	mw "gemma.intevation.de/gemma/pkg/middleware"
	"gemma.intevation.de/gemma/pkg/models"
)

// BindRoutes binds all the API endpoints to the exposed router.
func BindRoutes(m *mux.Router) {

	api := m.PathPrefix("/api").Subrouter()

	var (
		sysAdmin      = auth.EnsureRole("sys_admin")
		waterwayAdmin = auth.EnsureRole("waterway_admin")
		any           = auth.EnsureRole("sys_admin", "waterway_admin", "waterway_user")
	)

	// Password resets.
	api.Handle("/users/passwordreset", &mw.JSONHandler{
		Input:  func(*http.Request) interface{} { return new(models.PWResetUser) },
		Handle: passwordResetRequest,
		NoConn: true,
	}).Methods(http.MethodPost)

	api.HandleFunc("/users/passwordreset/{hash}", passwordReset).
		Methods(http.MethodGet)

	// User management.
	api.Handle("/users", any(&mw.JSONHandler{
		Handle: listUsers,
	})).Methods(http.MethodGet)

	api.Handle("/users", sysAdmin(&mw.JSONHandler{
		Input:  func(*http.Request) interface{} { return new(models.User) },
		Handle: createUser,
	})).Methods(http.MethodPost)

	api.Handle("/users/{user:.+}", any(&mw.JSONHandler{
		Handle: listUser,
	})).Methods(http.MethodGet)

	api.Handle("/users/{user:.+}", any(&mw.JSONHandler{
		Input:  func(*http.Request) interface{} { return new(models.User) },
		Handle: updateUser,
	})).Methods(http.MethodPut)

	api.Handle("/users/{user:.+}", any(&mw.JSONHandler{
		Input:  func(*http.Request) interface{} { return new(models.UserPatch) },
		Handle: patchUser,
	})).Methods(http.MethodPatch)

	api.Handle("/users/{user:.+}", sysAdmin(&mw.JSONHandler{
		Handle: deleteUser,
	})).Methods(http.MethodDelete)

	// System notifications
	api.Handle("/testmail/{user:.+}", sysAdmin(&mw.JSONHandler{
		Handle: sendTestMail,
	})).Methods(http.MethodGet)

	// System Management
	api.Handle("/system/log/{service}/{file}", sysAdmin(&mw.JSONHandler{
		Handle: showSystemLog,
		NoConn: true,
	})).Methods(http.MethodGet)

	// System Settings
	api.Handle("/system/config", any(&mw.JSONHandler{
		Handle: getSystemConfig,
		NoConn: true,
	})).Methods(http.MethodGet)

	api.Handle("/system/settings", any(&mw.JSONHandler{
		Handle: getSystemSettings,
	})).Methods(http.MethodGet)

	api.Handle("/system/settings", sysAdmin(&mw.JSONHandler{
		Input:  func(*http.Request) interface{} { return &map[string]string{} },
		Handle: setSystemSettings,
	})).Methods(http.MethodPut)

	// Print templates
	api.Handle("/templates", any(&mw.JSONHandler{
		Handle: listPrintTemplates,
	})).Methods(http.MethodGet)

	tTypes := "{type:" + strings.Join(templateTypes, "|") + "}"

	api.Handle("/templates/"+tTypes, any(&mw.JSONHandler{
		Handle: listPrintTemplates,
	})).Methods(http.MethodGet)

	api.Handle("/templates/"+tTypes+"/{name}", any(&mw.JSONHandler{
		Handle: fetchPrintTemplate,
	})).Methods(http.MethodGet)

	api.Handle("/templates/"+tTypes+"/{name}", waterwayAdmin(&mw.JSONHandler{
		Input:  func(*http.Request) interface{} { return &json.RawMessage{} },
		Handle: createPrintTemplate,
		Limit:  maxPrintTemplateSize,
	})).Methods(http.MethodPost)

	api.Handle("/templates/"+tTypes+"/{name}", waterwayAdmin(&mw.JSONHandler{
		Handle: deletePrintTemplate,
	})).Methods(http.MethodDelete)

	api.Handle("/templates/"+tTypes+"/{name}", waterwayAdmin(&mw.JSONHandler{
		Input:  func(*http.Request) interface{} { return &json.RawMessage{} },
		Handle: updatePrintTemplate,
		Limit:  maxPrintTemplateSize,
	})).Methods(http.MethodPatch)

	// External proxies.
	external := mw.NotFound(&httputil.ReverseProxy{
		Director:       proxyDirector(models.ExternalServices.Find),
		ModifyResponse: proxyModifyResponse("/api/external/"),
	})

	externalAuth := any(external)

	api.Handle("/external/{hash}/{url}", externalAuth).
		Methods(
			http.MethodGet, http.MethodPost,
			http.MethodPut, http.MethodDelete)

	api.Handle("/external/{entry}", externalAuth).
		Methods(
			http.MethodGet, http.MethodPost,
			http.MethodPut, http.MethodDelete)

	// Internal proxies.
	internal := mw.NotFound(&httputil.ReverseProxy{
		Director:       proxyDirector(models.InternalServices.Find),
		ModifyResponse: proxyModifyResponse("/api/internal/"),
	})

	internalAuth := any(
		mw.ModifyQuery(internal, mw.InjectUser))

	api.Handle("/internal/{hash}/{url}", internalAuth).
		Methods(
			http.MethodGet, http.MethodPost,
			http.MethodPut, http.MethodDelete)

	api.Handle("/internal/{entry}", internalAuth).
		Methods(
			http.MethodGet, http.MethodPost,
			http.MethodPut, http.MethodDelete)

	api.Handle("/published", any(&mw.JSONHandler{
		Handle: published,
		NoConn: true,
	})).Methods(http.MethodGet)

	// Survey selection
	api.Handle("/surveys/{bottleneck:.+}", any(&mw.JSONHandler{
		Handle: listSurveys,
	})).Methods(http.MethodGet)

	// difference calculation
	api.Handle("/diff", any(&mw.JSONHandler{
		Input:  func(*http.Request) interface{} { return new(models.DiffCalculationInput) },
		Handle: diffCalculation,
		NoConn: true,
	})).Methods(http.MethodPost)

	// Cross sections
	api.Handle("/cross", any(&mw.JSONHandler{
		Input:  func(*http.Request) interface{} { return new(models.CrossSectionInput) },
		Handle: crossSection,
	})).Methods(http.MethodPost)

	// Feature search
	api.Handle("/search", any(&mw.JSONHandler{
		Input:  func(*http.Request) interface{} { return new(models.SearchRequest) },
		Handle: searchFeature,
	})).Methods(http.MethodPost)

	// Geo styling
	api.Handle("/geo/style/{feature}",
		sysAdmin(http.HandlerFunc(uploadStyle))).Methods(http.MethodPost)

	// Imports
	api.Handle("/imports/sr-upload/{token}",
		waterwayAdmin(http.HandlerFunc(deleteSoundingUpload))).Methods(http.MethodDelete)

	api.Handle("/imports/sr-upload", waterwayAdmin(&mw.JSONHandler{
		Handle: uploadSoundingResult,
	})).Methods(http.MethodPost)

	api.Handle("/imports/sr", waterwayAdmin(
		http.HandlerFunc(importSoundingResult))).Methods(http.MethodPost)

	api.Handle("/imports/wp", waterwayAdmin(
		importWaterwayProfiles())).Methods(http.MethodPost)

	api.Handle("/imports/agm", waterwayAdmin(
		importApprovedGaugeMeasurements())).Methods(http.MethodPost)

	api.Handle("/imports/ubn", waterwayAdmin(
		importUploadedBottleneck())).Methods(http.MethodPost)

	api.Handle("/imports/ufa", waterwayAdmin(
		importUploadedFairwayAvailability())).Methods(http.MethodPost)

	api.Handle("/imports/ugm", waterwayAdmin(
		importUploadedGaugeMeasurement())).Methods(http.MethodPost)

	api.Handle("/imports/stsh", sysAdmin(
		importUploadedStretchShape())).Methods(http.MethodPost)

	api.Handle("/imports/{kind:st}", sysAdmin(&mw.JSONHandler{
		Input:  importModel,
		Handle: manualImport,
		NoConn: true,
	})).Methods(http.MethodPost)

	kinds := strings.Join([]string{
		"bn", "gm", "fa", "wx", "wa",
		"wg", "dmv", "fd", "dma",
		"sec", "dsec", "dst", "dsr",
		"fm_bcnlat_hydro",
		"fm_bcnlat_ienc",
		"fm_boycar",
		"fm_boylat_hydro",
		"fm_boylat_ienc",
		"fm_boysaw",
		"fm_boyspp",
		"fm_daymar_hydro",
		"fm_daymar_ienc",
		"fm_lights",
		"fm_rtpbcn",
		"fm_topmar",
		"fm_notmrk",
	}, "|")

	api.Handle("/imports/{kind:"+kinds+"}", waterwayAdmin(&mw.JSONHandler{
		Input:  importModel,
		Handle: manualImport,
		NoConn: true,
	})).Methods(http.MethodPost)

	api.Handle("/imports/{kind:report}", sysAdmin(&mw.JSONHandler{
		Input:  importModel,
		Handle: manualImport,
		NoConn: true,
	})).Methods(http.MethodPost)

	// Import scheduler configuration
	api.Handle("/imports/config/{id:[0-9]+}/run",
		waterwayAdmin(&mw.JSONHandler{
			Handle: runImportConfig,
		})).Methods(http.MethodGet)

	api.Handle("/imports/config/{id:[0-9]+}",
		waterwayAdmin(&mw.JSONHandler{
			Input:  func(*http.Request) interface{} { return &json.RawMessage{} },
			Handle: modifyImportConfig,
		})).Methods(http.MethodPatch)

	api.Handle("/imports/config/{id:[0-9]+}",
		waterwayAdmin(&mw.JSONHandler{
			Handle: deleteImportConfig,
		})).Methods(http.MethodDelete)

	api.Handle("/imports/config/{id:[0-9]+}",
		waterwayAdmin(&mw.JSONHandler{
			Handle: infoImportConfig,
		})).Methods(http.MethodGet)

	api.Handle("/imports/config",
		waterwayAdmin(&mw.JSONHandler{
			Input:  func(*http.Request) interface{} { return new(imports.ImportConfigIn) },
			Handle: addImportConfig,
		})).Methods(http.MethodPost)

	api.Handle("/imports/config",
		waterwayAdmin(&mw.JSONHandler{
			Handle: listImportConfigs,
		})).Methods(http.MethodGet)

	// Import queue

	api.Handle("/imports", waterwayAdmin(&mw.JSONHandler{
		Handle: listImports,
	})).Methods(http.MethodGet)

	api.Handle("/imports/export", waterwayAdmin(
		mw.DBConn(http.HandlerFunc(exportImports)))).Methods(http.MethodGet)

	api.Handle("/imports/{id:[0-9]+}", waterwayAdmin(&mw.JSONHandler{
		Handle: importLogs,
	})).Methods(http.MethodGet)

	api.Handle("/imports", waterwayAdmin(&mw.JSONHandler{
		Input:  func(*http.Request) interface{} { return &[]models.Review{} },
		Handle: reviewImports,
		NoConn: true,
	})).Methods(http.MethodPatch)

	api.Handle("/imports/{id:[0-9]+}", waterwayAdmin(&mw.JSONHandler{
		Handle: deleteImport,
	})).Methods(http.MethodDelete)

	// Handler to review an import which is pending.
	api.Handle("/imports/{id:[0-9]+}/{state:(?:accepted|declined)}",
		waterwayAdmin(&mw.JSONHandler{
			Handle: reviewImport,
			NoConn: true,
		})).Methods(http.MethodPut)

	// Handler for reporting

	api.Handle("/data/reports",
		waterwayAdmin(&mw.JSONHandler{
			Handle: listReports,
			NoConn: true,
		})).Methods(http.MethodGet)

	api.Handle("/data/report/{name:[a-zA-Z0-9_-]+}", waterwayAdmin(
		mw.DBConn(http.HandlerFunc(report)))).Methods(http.MethodGet)

	// Handler to serve data to the client.

	api.Handle("/data/{type:availability|fairway}/{kind:stretch|section|bottleneck}/{name:.+}", any(
		mw.DBConn(http.HandlerFunc(fairwayAvailability)))).Methods(http.MethodGet)

	api.Handle("/data/stretch/shape/{name:.+}", any(
		mw.DBConn(http.HandlerFunc(stretchShapeDownload)))).Methods(http.MethodGet)

	api.Handle("/data/waterlevels/{gauge:.+}", any(
		mw.DBConn(http.HandlerFunc(waterlevels)))).Methods(http.MethodGet)

	api.Handle("/data/longterm-waterlevels/{gauge:.+}", any(
		mw.DBConn(http.HandlerFunc(longtermWaterlevels)))).Methods(http.MethodGet)

	// TODO: gauge should not contain '/'s.
	api.Handle("/data/year-waterlevels/{gauge}/{year:[0-9]+}", any(
		mw.DBConn(http.HandlerFunc(yearWaterlevels)))).Methods(http.MethodGet)

	api.Handle("/data/nash-sutcliffe/{gauge:.+}", any(&mw.JSONHandler{
		Handle: nashSutcliffe,
	})).Methods(http.MethodGet)

	// Token handling: Login/Logout.
	api.HandleFunc("/login", login).
		Methods(http.MethodPost)
	api.Handle("/logout", auth.SessionMiddleware(http.HandlerFunc(logout))).
		Methods(http.MethodGet, http.MethodPost)
	api.Handle("/renew", auth.SessionMiddleware(http.HandlerFunc(renew))).
		Methods(http.MethodGet, http.MethodPost)
}