view pkg/controllers/routes.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 2b862190aee4
children 6270951dda28
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")
		anyUser       = 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", anyUser(&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:.+}", anyUser(&mw.JSONHandler{
		Handle: listUser,
	})).Methods(http.MethodGet)

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

	api.Handle("/users/{user:.+}", anyUser(&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", anyUser(&mw.JSONHandler{
		Handle: getSystemConfig,
		NoConn: true,
	})).Methods(http.MethodGet)

	api.Handle("/system/settings", anyUser(&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", anyUser(&mw.JSONHandler{
		Handle: listPrintTemplates,
	})).Methods(http.MethodGet)

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

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

	api.Handle("/templates/"+tTypes+"/{name}", anyUser(&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 := anyUser(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 := anyUser(
		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", anyUser(&mw.JSONHandler{
		Handle: published,
		NoConn: true,
	})).Methods(http.MethodGet)

	// Survey selection
	api.Handle("/surveys", anyUser(&mw.JSONHandler{
		Handle: listSurveys,
	})).Methods(http.MethodGet).Queries("id", "{id}")

	api.Handle("/surveys", anyUser(&mw.JSONHandler{
		Handle: listSurveys,
	})).Methods(http.MethodGet).Queries("name", "{name}", "date", "{date}")

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

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

	// Feature search
	api.Handle("/search", anyUser(&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|statsupdate}", 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",
		anyUser(&mw.JSONHandler{
			Handle: listReports,
			NoConn: true,
		})).Methods(http.MethodGet)

	api.Handle("/data/report/{name:"+models.SafePathExp+"}", waterwayAdmin(
		mw.DBConn(http.HandlerFunc(report)))).Methods(http.MethodGet)

	// Handler for update scripts
	api.Handle("/data/stats-updates",
		sysAdmin(&mw.JSONHandler{
			Handle: listStatsUpdates,
		})).Methods(http.MethodGet)

	api.Handle("/data/stats-updates/{name:.+}",
		sysAdmin(&mw.JSONHandler{
			Handle: statsUpdates,
		})).Methods(http.MethodGet)

	// Handler to serve data to the client.

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

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

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

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

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

	api.Handle("/data/nash-sutcliffe/{gauge:.+}", anyUser(&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)
}