Mercurial > gemma
changeset 5327:c008e13fa1d1 extented-report
Merged.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Sun, 30 May 2021 13:18:50 +0200 |
parents | 96ceb150ea46 (current diff) 313bf3f3a8b1 (diff) |
children | bc8c082487b2 |
files | pkg/controllers/routes.go |
diffstat | 6 files changed, 205 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- a/pkg/controllers/report.go Sun May 30 13:18:10 2021 +0200 +++ b/pkg/controllers/report.go Sun May 30 13:18:50 2021 +0200 @@ -19,15 +19,86 @@ "net/http" "os" "path/filepath" + "sort" + "strings" "gemma.intevation.de/gemma/pkg/config" "gemma.intevation.de/gemma/pkg/middleware" "gemma.intevation.de/gemma/pkg/xlsx" + mw "gemma.intevation.de/gemma/pkg/middleware" + "github.com/360EntSecGroup-Skylar/excelize/v2" "github.com/gorilla/mux" ) +func listReports(req *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.Printf("error: %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.Printf("error: %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()
--- a/pkg/controllers/routes.go Sun May 30 13:18:10 2021 +0200 +++ b/pkg/controllers/routes.go Sun May 30 13:18:50 2021 +0200 @@ -325,6 +325,12 @@ // 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)
--- a/pkg/xlsx/templater.go Sun May 30 13:18:10 2021 +0200 +++ b/pkg/xlsx/templater.go Sun May 30 13:18:50 2021 +0200 @@ -162,9 +162,9 @@ } func (e *executor) copy(action *Action) error { - if len(action.Location) != 2 { - return fmt.Errorf("length location = %d (expect 2)", - len(action.Source)) + if n := len(action.Location); !(n == 1 || n == 2) { + return fmt.Errorf("length location = %d (expect 1 or 2)", + len(action.Location)) } vars := e.vars() @@ -193,10 +193,26 @@ return a, b } + var location []string + + if len(action.Location) == 1 { + location = []string{action.Location[0], action.Location[0]} + } else { + location = action.Location + } + + var destination string + + if action.Destination == "" { + destination = location[0] + } else { + destination = action.Destination + } + var ( - s1 = expand(action.Location[0]) - s2 = expand(action.Location[1]) - d1 = expand(action.Destination) + s1 = expand(location[0]) + s2 = expand(location[1]) + d1 = expand(destination) sx1, sy1 = split(s1) sx2, sy2 = split(s2) dx1, dy1 = split(d1)
--- a/schema/gemma.sql Sun May 30 13:18:10 2021 +0200 +++ b/schema/gemma.sql Sun May 30 13:18:50 2021 +0200 @@ -384,7 +384,8 @@ -- keep username length compatible with role identifier country char(2) NOT NULL REFERENCES countries, map_extent box2d NOT NULL, - email_address varchar NOT NULL + email_address varchar NOT NULL, + report_reciever boolean NOT NULL DEFAULT false ) ; @@ -492,7 +493,8 @@ CAST('' AS varchar) AS pw, p.country, p.map_extent, - p.email_address + p.email_address, + p.report_reciever FROM internal.user_profiles p JOIN pg_roles u ON p.username = u.rolname JOIN pg_auth_members a ON u.oid = a.member
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/schema/updates/1450/01.report_reciever.sql Sun May 30 13:18:50 2021 +0200 @@ -0,0 +1,101 @@ +ALTER TABLE internal.user_profiles + ADD COLUMN report_reciever boolean NOT NULL DEFAULT false; + +CREATE OR REPLACE VIEW list_users WITH (security_barrier) AS + SELECT + r.rolname, + p.username, + CAST('' AS varchar) AS pw, + p.country, + p.map_extent, + p.email_address, + p.report_reciever + FROM internal.user_profiles p + JOIN pg_roles u ON p.username = u.rolname + JOIN pg_auth_members a ON u.oid = a.member + JOIN pg_roles r ON a.roleid = r.oid + WHERE p.username = current_user + OR pg_has_role('waterway_admin', 'MEMBER') + AND p.country = ( + SELECT country FROM internal.user_profiles + WHERE username = current_user) + AND r.rolname <> 'sys_admin' + OR pg_has_role('sys_admin', 'MEMBER') +; + +CREATE OR REPLACE FUNCTION internal.update_user() RETURNS trigger +AS $$ +DECLARE + cur_username varchar; +BEGIN + cur_username = OLD.username; + + IF NEW.username <> cur_username + THEN + EXECUTE format( + 'ALTER ROLE %I RENAME TO %I', cur_username, NEW.username); + cur_username = NEW.username; + END IF; + + UPDATE internal.user_profiles p + SET (username, country, map_extent, email_address, report_reciever) + = (NEW.username, NEW.country, NEW.map_extent, NEW.email_address, NEW.report_reciever) + WHERE p.username = cur_username; + + IF NEW.rolname <> OLD.rolname + THEN + EXECUTE format( + 'REVOKE %I FROM %I', OLD.rolname, cur_username); + EXECUTE format( + 'GRANT %I TO %I', NEW.rolname, cur_username); + END IF; + + IF NEW.pw IS NOT NULL AND NEW.pw <> '' + THEN + EXECUTE format( + 'ALTER ROLE %I PASSWORD %L', + cur_username, + internal.check_password(NEW.pw)); + END IF; + + -- Do not leak new password + NEW.pw = ''; + RETURN NEW; +END; +$$ + LANGUAGE plpgsql + SECURITY DEFINER; + +CREATE OR REPLACE FUNCTION internal.create_user() RETURNS trigger +AS $$ +BEGIN + IF NEW.map_extent IS NULL + THEN + NEW.map_extent = ST_Extent(CAST(area AS geometry)) + FROM users.stretches st + JOIN users.stretch_countries stc ON stc.stretch_id = st.id + WHERE stc.country = NEW.country; + END IF; + + IF NEW.username IS NOT NULL + -- otherwise let the constraint on user_profiles speak + THEN + EXECUTE format( + 'CREATE ROLE %I IN ROLE %I LOGIN PASSWORD %L', + NEW.username, + NEW.rolname, + internal.check_password(NEW.pw)); + END IF; + + INSERT INTO internal.user_profiles ( + username, country, map_extent, email_address, report_reciever) + VALUES (NEW.username, NEW.country, NEW.map_extent, NEW.email_address, NEW.report_reciever); + + -- Do not leak new password + NEW.pw = ''; + RETURN NEW; +END; +$$ + LANGUAGE plpgsql + SECURITY DEFINER; +