# HG changeset patch # User Raimund Renkert # Date 1545404188 -3600 # Node ID d8ca44615bfcea426751da2f5d9c6e89b6117b6c # Parent 51a0ba4ede41139c473ad8d9a9dbca8e99200c31 Implemented first version of fairway availability import. diff -r 51a0ba4ede41 -r d8ca44615bfc pkg/controllers/faimports.go --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/controllers/faimports.go Fri Dec 21 15:56:28 2018 +0100 @@ -0,0 +1,70 @@ +// 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 by via donau +// – Österreichische Wasserstraßen-Gesellschaft mbH +// Software engineering by Intevation GmbH +// +// Author(s): +// * Raimund Renkert + +package controllers + +import ( + "database/sql" + "log" + "net/http" + + "gemma.intevation.de/gemma/pkg/auth" + "gemma.intevation.de/gemma/pkg/common" + "gemma.intevation.de/gemma/pkg/imports" + "gemma.intevation.de/gemma/pkg/models" +) + +func importFairwayAvailability( + input interface{}, + req *http.Request, + conn *sql.Conn, +) (jr JSONResult, err error) { + + fai := input.(*models.FairwayAvailabilityImport) + + fa := &imports.FairwayAvailability{ + URL: fai.URL, + Insecure: fai.Insecure, + } + + var serialized string + if serialized, err = common.ToJSONString(fa); err != nil { + return + } + + session, _ := auth.GetSession(req) + + var jobID int64 + if jobID, err = imports.AddJob( + imports.FAJobKind, + session.User, + fai.SendEmail, true, + serialized, + ); err != nil { + return + } + + log.Printf("info: added import #%d to queue\n", jobID) + + result := struct { + ID int64 `json:"id"` + }{ + ID: jobID, + } + + jr = JSONResult{ + Code: http.StatusCreated, + Result: &result, + } + return +} diff -r 51a0ba4ede41 -r d8ca44615bfc pkg/controllers/routes.go --- a/pkg/controllers/routes.go Fri Dec 21 14:15:33 2018 +0100 +++ b/pkg/controllers/routes.go Fri Dec 21 15:56:28 2018 +0100 @@ -181,6 +181,11 @@ Handle: importGaugeMeasurement, })).Methods(http.MethodPost) + api.Handle("/imports/fairwayavailability", waterwayAdmin(&JSONHandler{ + Input: func() interface{} { return new(models.FairwayAvailabilityImport) }, + Handle: importFairwayAvailability, + })).Methods(http.MethodPost) + // Import scheduler configuration api.Handle("/imports/config/{id:[0-9]+}", waterwayAdmin(&JSONHandler{ diff -r 51a0ba4ede41 -r d8ca44615bfc pkg/imports/fa.go --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/imports/fa.go Fri Dec 21 15:56:28 2018 +0100 @@ -0,0 +1,366 @@ +// 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 by via donau +// – Österreichische Wasserstraßen-Gesellschaft mbH +// Software engineering by Intevation GmbH +// +// Author(s): +// * Raimund Renkert +package imports + +import ( + "context" + "database/sql" + "errors" + "time" + + "gemma.intevation.de/gemma/pkg/common" + "gemma.intevation.de/gemma/pkg/models" + "gemma.intevation.de/gemma/pkg/soap/ifaf" + "github.com/jackc/pgx/pgtype" +) + +type FairwayAvailability struct { + URL string `json:"url"` + Insecure bool `json:"insecure"` +} + +const FAJobKind JobKind = "fa" + +const ( + listBottlenecksSQL = ` +SELECT + bottleneck_id, + responsible_country +FROM waterway.bottlenecks +WHERE responsible_country = users.current_user_country() + AND staging_done = true +` + insertFASQL = ` +INSERT INTO waterway.fairway_availability ( + position_code, + bottleneck_id, + surdat, + critical, + date_info, + source_organization +) VALUES ( + $1, + (SELECT id FROM waterway.bottlenecks WHERE bottleneck_id = $2), + $3, + $4, + $5, + $6 +) +RETURNING id` + + insertBnPdfsSQL = ` +INSERT INTO waterway.bottleneck_pdfs ( + fairway_availability_id, + profile_pdf_filename, + profile_pdf_url, + pdf_generation_date, + source_organization +) VALUES ( + $1, + $2, + $3, + $4, + $5 +)` + insertEFASQL = ` +INSERT INTO waterway.effective_fairway_availability ( + fairway_availability_id, + measure_date, + level_of_service, + available_depth_value, + available_width_value, + water_level_value, + measure_type, + source_organization, + forecast_generation_time, + value_lifetime +) VALUES ( + $1, + $2, + (SELECT + level_of_service + FROM levels_of_service + WHERE name = $3), + $4, + $5, + $6, + $7, + $8, + $9, + $10 +)` + insertFAVSQL = ` +INSERT INTO waterway.fa_reference_values ( + fairway_availability_id, + level_of_service, + fairway_depth, + fairway_width, + fairway_radius, + shallowest_spot +) VALUES ( + $1, + (SELECT + level_of_service + FROM levels_of_service + WHERE name = $2), + $3, + $4, + $5, + ST_MakePoint($6, $7)::geography +)` +) + +type faJobCreator struct{} + +func init() { + RegisterJobCreator(FAJobKind, faJobCreator{}) +} + +func (faJobCreator) Description() string { + return "fairway availability" +} + +func (faJobCreator) Create(_ JobKind, data string) (Job, error) { + fa := new(FairwayAvailability) + if err := common.FromJSONString(data, fa); err != nil { + return nil, err + } + return fa, nil +} + +func (faJobCreator) Depends() []string { + return []string{ + "bottlenecks", + "fairway_availability", + "bottleneck_pdfs", + "effective_fairway_availability", + "fa_reference_values", + "levels_of_service", + } +} + +// StageDone moves the imported fairway availablities out of the staging area. +// Currently doing nothing. +func (faJobCreator) StageDone( + ctx context.Context, + tx *sql.Tx, + id int64, +) error { + return nil +} + +// CleanUp of a fairway availablities import is a NOP. +func (fa *FairwayAvailability) CleanUp() error { return nil } + +// Do executes the actual fairway availability import. +func (fa *FairwayAvailability) Do( + ctx context.Context, + importID int64, + conn *sql.Conn, + feedback Feedback, +) (interface{}, error) { + + // Get available bottlenecks from database for use as filter in SOAP request + var rows *sql.Rows + + rows, err := conn.QueryContext(ctx, listBottlenecksSQL) + if err != nil { + return nil, err + } + defer rows.Close() + + bottlenecks := []models.Bottleneck{} + + for rows.Next() { + var bn models.Bottleneck + if err = rows.Scan( + &bn.ID, + &bn.ResponsibleCountry, + ); err != nil { + return nil, err + } + bottlenecks = append(bottlenecks, bn) + } + + if err = rows.Err(); err != nil { + return nil, err + } + + faids, err := fa.doForFAs(ctx, bottlenecks, conn, feedback) + if err != nil { + feedback.Error("Error processing data: %s", err) + } + if len(faids) == 0 { + feedback.Info("No new fairway availablity data found") + return nil, nil + } + feedback.Info("Processed %d of %d bottlenecks", len(faids), len(bottlenecks)) + // TODO: needs to be filled more useful. + summary := struct { + FairwayAvailabilities []string `json:"fairwayAvailabilities"` + }{ + FairwayAvailabilities: faids, + } + return &summary, err +} + +func (fa *FairwayAvailability) doForFAs( + ctx context.Context, + bottlenecks []models.Bottleneck, + conn *sql.Conn, + feedback Feedback, +) ([]string, error) { + start := time.Now() + + client := ifaf.NewFairwayAvailabilityService(fa.URL, fa.Insecure, nil) + + var bnIds []string + for _, bn := range bottlenecks { + bnIds = append(bnIds, bn.ID) + } + + ids := ifaf.ArrayOfString{ + String: bnIds, + } + + // TODO: Filter by period. Period should start after latest measurement date. + req := &ifaf.Get_bottleneck_fa{ + Bottleneck_id: &ids, + } + resp, err := client.Get_bottleneck_fa(req) + if err != nil { + feedback.Error("%v", err) + return nil, err + } + + if resp.Get_bottleneck_faResult == nil { + err := errors.New("no fairway availabilities found") + return nil, err + } + + result := resp.Get_bottleneck_faResult + + tx, err := conn.BeginTx(ctx, nil) + if err != nil { + return nil, err + } + defer tx.Rollback() + + insertFAStmt, err := tx.PrepareContext(ctx, insertFASQL) + if err != nil { + return nil, err + } + defer insertFAStmt.Close() + insertBnPdfsStmt, err := tx.PrepareContext(ctx, insertBnPdfsSQL) + if err != nil { + return nil, err + } + defer insertBnPdfsStmt.Close() + insertEFAStmt, err := tx.PrepareContext(ctx, insertEFASQL) + if err != nil { + return nil, err + } + defer insertEFAStmt.Close() + insertFAVStmt, err := tx.PrepareContext(ctx, insertFAVSQL) + if err != nil { + return nil, err + } + defer insertFAVStmt.Close() + + var faids []string + var faId int64 + feedback.Info("Found %d fairway availabilities", len(result.FairwayAvailability)) + for _, faRes := range result.FairwayAvailability { + // TODO: high frequent requests lead to "duplicate key value violates unique constraint "fairway_availability_bottleneck_id_surdat_key" + // in the database. This has to be resolved. + // All data subsets can also ocure as duplicates! + err = insertFAStmt.QueryRowContext( + ctx, + faRes.POSITION, + faRes.Bottleneck_id, + faRes.SURDAT, + faRes.Critical, + faRes.Date_Info, + faRes.Source, + ).Scan(&faId) + if err != nil { + return nil, err + } + feedback.Info("Processing for Bottleneck %s", faRes.Bottleneck_id) + faids = append(faids, faRes.Bottleneck_id) + for _, bnPdfs := range faRes.Bottleneck_PDFs.PdfInfo { + _, err = insertBnPdfsStmt.ExecContext( + ctx, + faId, + bnPdfs.ProfilePdfFilename, + bnPdfs.ProfilePdfURL, + bnPdfs.PDF_Generation_Date, + bnPdfs.Source, + ) + if err != nil { + return nil, err + } + feedback.Info("Add %d Pdfs", len(faRes.Bottleneck_PDFs.PdfInfo)) + } + for _, efa := range faRes.Effective_fairway_availability.EffectiveFairwayAvailability { + los := efa.Level_of_Service + fgt := efa.Forecast_generation_time + if efa.Forecast_generation_time.Status == pgtype.Undefined { + fgt = pgtype.Timestamp{ + Status: pgtype.Null, + } + } + _, err = insertEFAStmt.ExecContext( + ctx, + faId, + efa.Measure_date, + string(*los), + efa.Available_depth_value, + efa.Available_width_value, + efa.Water_level_value, + efa.Measure_type, + efa.Source, + fgt, + efa.Value_lifetime, + ) + if err != nil { + return nil, err + } + feedback.Info("Add %d Effective Fairway Availability", len( + faRes.Effective_fairway_availability.EffectiveFairwayAvailability)) + } + for _, fav := range faRes.Reference_values.ReferenceValue { + _, err = insertFAVStmt.ExecContext( + ctx, + faId, + fav.Level_of_Service, + fav.Fairway_depth, + fav.Fairway_width, + fav.Fairway_radius, + fav.Shallowest_spot_Lat, + fav.Shallowest_spot_Lon, + ) + if err != nil { + return nil, err + } + feedback.Info("Add %d Reference Values", + len(faRes.Reference_values.ReferenceValue)) + } + } + feedback.Info("Storing fairway availabilities took %s", time.Since(start)) + if err = tx.Commit(); err == nil { + feedback.Info("Import of fairway availabilities was successful") + } + + return faids, nil +} diff -r 51a0ba4ede41 -r d8ca44615bfc pkg/models/bn.go --- a/pkg/models/bn.go Fri Dec 21 14:15:33 2018 +0100 +++ b/pkg/models/bn.go Fri Dec 21 15:56:28 2018 +0100 @@ -18,3 +18,8 @@ Insecure bool `json:"insecure"` SendEmail bool `json:"send-email"` } + +type Bottleneck struct { + ID string + ResponsibleCountry string +} diff -r 51a0ba4ede41 -r d8ca44615bfc pkg/models/fa.go --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/models/fa.go Fri Dec 21 15:56:28 2018 +0100 @@ -0,0 +1,21 @@ +// 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 by via donau +// – Österreichische Wasserstraßen-Gesellschaft mbH +// Software engineering by Intevation GmbH +// +// Author(s): +// * Raimund Renkert + +package models + +// FairwayAvailabilityImport contains data used to define the endpoint +type FairwayAvailabilityImport struct { + URL string `json:"url"` + Insecure bool `json:"insecure"` + SendEmail bool `json:"send-email"` +} diff -r 51a0ba4ede41 -r d8ca44615bfc pkg/soap/ifaf/service.go --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/soap/ifaf/service.go Fri Dec 21 15:56:28 2018 +0100 @@ -0,0 +1,935 @@ +// 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 by via donau +// – Österreichische Wasserstraßen-Gesellschaft mbH +// Software engineering by Intevation GmbH +// +// Author(s): +// * Raimund Renkert + +package ifaf + +import ( + "crypto/tls" + "encoding/xml" + "time" + + "github.com/jackc/pgx/pgtype" + + "gemma.intevation.de/gemma/pkg/soap" +) + +// against "unused imports" +var _ time.Time +var _ xml.Name + +type Get_bottleneck_fa struct { + XMLName xml.Name `xml:"http://www.ris.eu/fairwayavailability/3.0 get_bottleneck_fa"` + + Bottleneck_id *ArrayOfString `xml:"bottleneck_id,omitempty"` + + Period *RequestedPeriod `xml:"period,omitempty"` +} + +type Get_bottleneck_faResponse struct { + XMLName xml.Name `xml:"http://www.ris.eu/fairwayavailability/3.0 get_bottleneck_faResponse"` + + Get_bottleneck_faResult *ArrayOfFairwayAvailability `xml:"get_bottleneck_faResult,omitempty"` +} + +type Get_stretch_fa struct { + XMLName xml.Name `xml:"http://www.ris.eu/fairwayavailability/3.0 get_stretch_fa"` + + ISRS *ArrayOfISRSPair `xml:"ISRS,omitempty"` + + Period *RequestedPeriod `xml:"period,omitempty"` +} + +type Get_stretch_faResponse struct { + XMLName xml.Name `xml:"http://www.ris.eu/fairwayavailability/3.0 get_stretch_faResponse"` + + Get_stretch_faResult *ArrayOfFairwayAvailability `xml:"get_stretch_faResult,omitempty"` +} + +type ArrayOfFairwayAvailability struct { + FairwayAvailability []*FairwayAvailability `xml:"FairwayAvailability,omitempty"` +} + +type FairwayAvailability struct { + Bottleneck_id string `xml:"bottleneck_id,omitempty"` + + SURDAT time.Time `xml:"SURDAT,omitempty"` + + POSITION *PositionEnum `xml:"POSITION,omitempty"` + + Reference_values *ArrayOfReferenceValue `xml:"Reference_values,omitempty"` + + AdditionalData *ArrayOfKeyValuePair `xml:"AdditionalData,omitempty"` + + Critical bool `xml:"Critical,omitempty"` + + Bottleneck_PDFs *ArrayOfPdfInfo `xml:"Bottleneck_PDFs,omitempty"` + + Effective_fairway_availability *ArrayOfEffectiveFairwayAvailability `xml:"Effective_fairway_availability,omitempty"` + + Date_Info time.Time `xml:"Date_Info,omitempty"` + + Source string `xml:"Source,omitempty"` +} + +type ArrayOfPdfInfo struct { + PdfInfo []*PdfInfo `xml:"PdfInfo,omitempty"` +} + +type PdfInfo struct { + ProfilePdfFilename string `xml:"ProfilePdfFilename,omitempty"` + + ProfilePdfURL string `xml:"ProfilePdfURL,omitempty"` + + PDF_Generation_Date time.Time `xml:"PDF_Generation_Date,omitempty"` + + Source string `xml:"Source,omitempty"` +} + +type ArrayOfEffectiveFairwayAvailability struct { + EffectiveFairwayAvailability []*EffectiveFairwayAvailability `xml:"EffectiveFairwayAvailability,omitempty"` +} + +type EffectiveFairwayAvailability struct { + Available_depth_value int32 `xml:"Available_depth_value,omitempty"` + + Available_width_value int32 `xml:"Available_width_value,omitempty"` + + Water_level_value int32 `xml:"Water_level_value,omitempty"` + + Measure_date time.Time `xml:"Measure_date,omitempty"` + + Measure_type *MeasureType `xml:"Measure_type,omitempty"` + + Source string `xml:"Source,omitempty"` + + Level_of_Service *LosEnum `xml:"Level_of_Service,omitempty"` + + Forecast_generation_time pgtype.Timestamp `xml:"Forecast_generation_time,omitempty"` + + Value_lifetime time.Time `xml:"Value_lifetime,omitempty"` +} + +type ArrayOfReferenceValue struct { + ReferenceValue []*ReferenceValue `xml:"ReferenceValue,omitempty"` +} + +type ReferenceValue struct { + Fairway_depth int32 `xml:"fairway_depth,omitempty"` + + Fairway_width int32 `xml:"fairway_width,omitempty"` + + Fairway_radius int32 `xml:"fairway_radius,omitempty"` + + Shallowest_spot_Lat float64 `xml:"Shallowest_spot_Lat,omitempty"` + + Shallowest_spot_Lon float64 `xml:"Shallowest_spot_Lon,omitempty"` + + Level_of_Service *LosEnum `xml:"Level_of_Service,omitempty"` +} + +type ErrorCode string + +const ( + + // Description: message type not supported, Explanation: + // web service does not support the requested message type + // + ErrorCodeE010 ErrorCode = "e010" + + // Description: syntax error in request, Explanation: + // request violates the schema for requests + ErrorCodeE100 ErrorCode = "e100" + + // Description: incorrect message type, Explanation: given + // message type is not known + ErrorCodeE110 ErrorCode = "e110" + + // Description: incorrect type-specific parameters, + // Explanation: type-specific parameters are erroneous + ErrorCodeE120 ErrorCode = "e120" + + // Description: operation not known, Explanation: the + // requested operation is unknown + ErrorCodeE200 ErrorCode = "e200" + + // Description: requested method or operation is not + // implemented + ErrorCodeE210 ErrorCode = "e210" + + // Description: data source unavailable, Explanation: data + // source of the web service for is temporarily unavailable + // + ErrorCodeE300 ErrorCode = "e300" + + // Description: too many results for request, Explanation: + // server is unable to handle number of results + ErrorCodeE310 ErrorCode = "e310" + + // Description: unexpected or other error + // + ErrorCodeE999 ErrorCode = "e999" +) + +type CountryCode string + +const ( + CountryCodeAF CountryCode = "AF" + + CountryCodeAX CountryCode = "AX" + + CountryCodeAL CountryCode = "AL" + + CountryCodeDZ CountryCode = "DZ" + + CountryCodeAS CountryCode = "AS" + + CountryCodeAD CountryCode = "AD" + + CountryCodeAO CountryCode = "AO" + + CountryCodeAI CountryCode = "AI" + + CountryCodeAQ CountryCode = "AQ" + + CountryCodeAG CountryCode = "AG" + + CountryCodeAR CountryCode = "AR" + + CountryCodeAM CountryCode = "AM" + + CountryCodeAW CountryCode = "AW" + + CountryCodeAU CountryCode = "AU" + + CountryCodeAT CountryCode = "AT" + + CountryCodeAZ CountryCode = "AZ" + + CountryCodeBS CountryCode = "BS" + + CountryCodeBH CountryCode = "BH" + + CountryCodeBD CountryCode = "BD" + + CountryCodeBB CountryCode = "BB" + + CountryCodeBY CountryCode = "BY" + + CountryCodeBE CountryCode = "BE" + + CountryCodeBZ CountryCode = "BZ" + + CountryCodeBJ CountryCode = "BJ" + + CountryCodeBM CountryCode = "BM" + + CountryCodeBT CountryCode = "BT" + + CountryCodeBO CountryCode = "BO" + + CountryCodeBQ CountryCode = "BQ" + + CountryCodeBA CountryCode = "BA" + + CountryCodeBW CountryCode = "BW" + + CountryCodeBV CountryCode = "BV" + + CountryCodeBR CountryCode = "BR" + + CountryCodeIO CountryCode = "IO" + + CountryCodeBN CountryCode = "BN" + + CountryCodeBG CountryCode = "BG" + + CountryCodeBF CountryCode = "BF" + + CountryCodeBI CountryCode = "BI" + + CountryCodeCV CountryCode = "CV" + + CountryCodeKH CountryCode = "KH" + + CountryCodeCM CountryCode = "CM" + + CountryCodeCA CountryCode = "CA" + + CountryCodeKY CountryCode = "KY" + + CountryCodeCF CountryCode = "CF" + + CountryCodeTD CountryCode = "TD" + + CountryCodeCL CountryCode = "CL" + + CountryCodeCN CountryCode = "CN" + + CountryCodeCX CountryCode = "CX" + + CountryCodeCC CountryCode = "CC" + + CountryCodeCO CountryCode = "CO" + + CountryCodeKM CountryCode = "KM" + + CountryCodeCG CountryCode = "CG" + + CountryCodeCD CountryCode = "CD" + + CountryCodeCK CountryCode = "CK" + + CountryCodeCR CountryCode = "CR" + + CountryCodeCI CountryCode = "CI" + + CountryCodeHR CountryCode = "HR" + + CountryCodeCU CountryCode = "CU" + + CountryCodeCW CountryCode = "CW" + + CountryCodeCY CountryCode = "CY" + + CountryCodeCZ CountryCode = "CZ" + + CountryCodeDK CountryCode = "DK" + + CountryCodeDJ CountryCode = "DJ" + + CountryCodeDM CountryCode = "DM" + + CountryCodeDO CountryCode = "DO" + + CountryCodeEC CountryCode = "EC" + + CountryCodeEG CountryCode = "EG" + + CountryCodeSV CountryCode = "SV" + + CountryCodeGQ CountryCode = "GQ" + + CountryCodeER CountryCode = "ER" + + CountryCodeEE CountryCode = "EE" + + CountryCodeET CountryCode = "ET" + + CountryCodeFK CountryCode = "FK" + + CountryCodeFO CountryCode = "FO" + + CountryCodeFJ CountryCode = "FJ" + + CountryCodeFI CountryCode = "FI" + + CountryCodeFR CountryCode = "FR" + + CountryCodeGF CountryCode = "GF" + + CountryCodePF CountryCode = "PF" + + CountryCodeTF CountryCode = "TF" + + CountryCodeGA CountryCode = "GA" + + CountryCodeGM CountryCode = "GM" + + CountryCodeGE CountryCode = "GE" + + CountryCodeDE CountryCode = "DE" + + CountryCodeGH CountryCode = "GH" + + CountryCodeGI CountryCode = "GI" + + CountryCodeGR CountryCode = "GR" + + CountryCodeGL CountryCode = "GL" + + CountryCodeGD CountryCode = "GD" + + CountryCodeGP CountryCode = "GP" + + CountryCodeGU CountryCode = "GU" + + CountryCodeGT CountryCode = "GT" + + CountryCodeGG CountryCode = "GG" + + CountryCodeGN CountryCode = "GN" + + CountryCodeGW CountryCode = "GW" + + CountryCodeGY CountryCode = "GY" + + CountryCodeHT CountryCode = "HT" + + CountryCodeHM CountryCode = "HM" + + CountryCodeVA CountryCode = "VA" + + CountryCodeHN CountryCode = "HN" + + CountryCodeHK CountryCode = "HK" + + CountryCodeHU CountryCode = "HU" + + CountryCodeIS CountryCode = "IS" + + CountryCodeIN CountryCode = "IN" + + CountryCodeID CountryCode = "ID" + + CountryCodeIR CountryCode = "IR" + + CountryCodeIQ CountryCode = "IQ" + + CountryCodeIE CountryCode = "IE" + + CountryCodeIM CountryCode = "IM" + + CountryCodeIL CountryCode = "IL" + + CountryCodeIT CountryCode = "IT" + + CountryCodeJM CountryCode = "JM" + + CountryCodeJP CountryCode = "JP" + + CountryCodeJE CountryCode = "JE" + + CountryCodeJO CountryCode = "JO" + + CountryCodeKZ CountryCode = "KZ" + + CountryCodeKE CountryCode = "KE" + + CountryCodeKI CountryCode = "KI" + + CountryCodeKP CountryCode = "KP" + + CountryCodeKR CountryCode = "KR" + + CountryCodeKW CountryCode = "KW" + + CountryCodeKG CountryCode = "KG" + + CountryCodeLA CountryCode = "LA" + + CountryCodeLV CountryCode = "LV" + + CountryCodeLB CountryCode = "LB" + + CountryCodeLS CountryCode = "LS" + + CountryCodeLR CountryCode = "LR" + + CountryCodeLY CountryCode = "LY" + + CountryCodeLI CountryCode = "LI" + + CountryCodeLT CountryCode = "LT" + + CountryCodeLU CountryCode = "LU" + + CountryCodeMO CountryCode = "MO" + + CountryCodeMK CountryCode = "MK" + + CountryCodeMG CountryCode = "MG" + + CountryCodeMW CountryCode = "MW" + + CountryCodeMY CountryCode = "MY" + + CountryCodeMV CountryCode = "MV" + + CountryCodeML CountryCode = "ML" + + CountryCodeMT CountryCode = "MT" + + CountryCodeMH CountryCode = "MH" + + CountryCodeMQ CountryCode = "MQ" + + CountryCodeMR CountryCode = "MR" + + CountryCodeMU CountryCode = "MU" + + CountryCodeYT CountryCode = "YT" + + CountryCodeMX CountryCode = "MX" + + CountryCodeFM CountryCode = "FM" + + CountryCodeMD CountryCode = "MD" + + CountryCodeMC CountryCode = "MC" + + CountryCodeMN CountryCode = "MN" + + CountryCodeME CountryCode = "ME" + + CountryCodeMS CountryCode = "MS" + + CountryCodeMA CountryCode = "MA" + + CountryCodeMZ CountryCode = "MZ" + + CountryCodeMM CountryCode = "MM" + + CountryCodeNA CountryCode = "NA" + + CountryCodeNR CountryCode = "NR" + + CountryCodeNP CountryCode = "NP" + + CountryCodeNL CountryCode = "NL" + + CountryCodeNC CountryCode = "NC" + + CountryCodeNZ CountryCode = "NZ" + + CountryCodeNI CountryCode = "NI" + + CountryCodeNE CountryCode = "NE" + + CountryCodeNG CountryCode = "NG" + + CountryCodeNU CountryCode = "NU" + + CountryCodeNF CountryCode = "NF" + + CountryCodeMP CountryCode = "MP" + + CountryCodeNO CountryCode = "NO" + + CountryCodeOM CountryCode = "OM" + + CountryCodePK CountryCode = "PK" + + CountryCodePW CountryCode = "PW" + + CountryCodePS CountryCode = "PS" + + CountryCodePA CountryCode = "PA" + + CountryCodePG CountryCode = "PG" + + CountryCodePY CountryCode = "PY" + + CountryCodePE CountryCode = "PE" + + CountryCodePH CountryCode = "PH" + + CountryCodePN CountryCode = "PN" + + CountryCodePL CountryCode = "PL" + + CountryCodePT CountryCode = "PT" + + CountryCodePR CountryCode = "PR" + + CountryCodeQA CountryCode = "QA" + + CountryCodeRE CountryCode = "RE" + + CountryCodeRO CountryCode = "RO" + + CountryCodeRU CountryCode = "RU" + + CountryCodeRW CountryCode = "RW" + + CountryCodeBL CountryCode = "BL" + + CountryCodeSH CountryCode = "SH" + + CountryCodeKN CountryCode = "KN" + + CountryCodeLC CountryCode = "LC" + + CountryCodeMF CountryCode = "MF" + + CountryCodePM CountryCode = "PM" + + CountryCodeVC CountryCode = "VC" + + CountryCodeWS CountryCode = "WS" + + CountryCodeSM CountryCode = "SM" + + CountryCodeST CountryCode = "ST" + + CountryCodeSA CountryCode = "SA" + + CountryCodeSN CountryCode = "SN" + + CountryCodeRS CountryCode = "RS" + + CountryCodeSC CountryCode = "SC" + + CountryCodeSL CountryCode = "SL" + + CountryCodeSG CountryCode = "SG" + + CountryCodeSX CountryCode = "SX" + + CountryCodeSK CountryCode = "SK" + + CountryCodeSI CountryCode = "SI" + + CountryCodeSB CountryCode = "SB" + + CountryCodeSO CountryCode = "SO" + + CountryCodeZA CountryCode = "ZA" + + CountryCodeGS CountryCode = "GS" + + CountryCodeSS CountryCode = "SS" + + CountryCodeES CountryCode = "ES" + + CountryCodeLK CountryCode = "LK" + + CountryCodeSD CountryCode = "SD" + + CountryCodeSR CountryCode = "SR" + + CountryCodeSJ CountryCode = "SJ" + + CountryCodeSZ CountryCode = "SZ" + + CountryCodeSE CountryCode = "SE" + + CountryCodeCH CountryCode = "CH" + + CountryCodeSY CountryCode = "SY" + + CountryCodeTW CountryCode = "TW" + + CountryCodeTJ CountryCode = "TJ" + + CountryCodeTZ CountryCode = "TZ" + + CountryCodeTH CountryCode = "TH" + + CountryCodeTL CountryCode = "TL" + + CountryCodeTG CountryCode = "TG" + + CountryCodeTK CountryCode = "TK" + + CountryCodeTO CountryCode = "TO" + + CountryCodeTT CountryCode = "TT" + + CountryCodeTN CountryCode = "TN" + + CountryCodeTR CountryCode = "TR" + + CountryCodeTM CountryCode = "TM" + + CountryCodeTC CountryCode = "TC" + + CountryCodeTV CountryCode = "TV" + + CountryCodeUG CountryCode = "UG" + + CountryCodeUA CountryCode = "UA" + + CountryCodeAE CountryCode = "AE" + + CountryCodeGB CountryCode = "GB" + + CountryCodeUS CountryCode = "US" + + CountryCodeUM CountryCode = "UM" + + CountryCodeUY CountryCode = "UY" + + CountryCodeUZ CountryCode = "UZ" + + CountryCodeVU CountryCode = "VU" + + CountryCodeVE CountryCode = "VE" + + CountryCodeVN CountryCode = "VN" + + CountryCodeVG CountryCode = "VG" + + CountryCodeVI CountryCode = "VI" + + CountryCodeWF CountryCode = "WF" + + CountryCodeEH CountryCode = "EH" + + CountryCodeYE CountryCode = "YE" + + CountryCodeZM CountryCode = "ZM" + + CountryCodeZW CountryCode = "ZW" +) + +type CoverageEnum string + +const ( + CoverageEnumCrossProfiles CoverageEnum = "CrossProfiles" + + CoverageEnumLongitudinalProfiles CoverageEnum = "LongitudinalProfiles" + + CoverageEnumFairway CoverageEnum = "Fairway" + + CoverageEnumRiver CoverageEnum = "River" + + CoverageEnumRiverBanks CoverageEnum = "RiverBanks" +) + +type DepthReferenceEnum string + +const ( + DepthReferenceEnumNAP DepthReferenceEnum = "NAP" + + DepthReferenceEnumKP DepthReferenceEnum = "KP" + + DepthReferenceEnumFZP DepthReferenceEnum = "FZP" + + DepthReferenceEnumADR DepthReferenceEnum = "ADR" + + DepthReferenceEnumTAW DepthReferenceEnum = "TAW" + + DepthReferenceEnumPUL DepthReferenceEnum = "PUL" + + DepthReferenceEnumNGM DepthReferenceEnum = "NGM" + + DepthReferenceEnumETRS DepthReferenceEnum = "ETRS" + + DepthReferenceEnumPOT DepthReferenceEnum = "POT" + + DepthReferenceEnumLDC DepthReferenceEnum = "LDC" + + DepthReferenceEnumHDC DepthReferenceEnum = "HDC" + + DepthReferenceEnumZPG DepthReferenceEnum = "ZPG" + + DepthReferenceEnumGLW DepthReferenceEnum = "GLW" + + DepthReferenceEnumHSW DepthReferenceEnum = "HSW" + + DepthReferenceEnumLNW DepthReferenceEnum = "LNW" + + DepthReferenceEnumHNW DepthReferenceEnum = "HNW" + + DepthReferenceEnumIGN DepthReferenceEnum = "IGN" + + DepthReferenceEnumWGS DepthReferenceEnum = "WGS" + + DepthReferenceEnumRN DepthReferenceEnum = "RN" + + DepthReferenceEnumHBO DepthReferenceEnum = "HBO" +) + +type LimitingFactorEnum string + +const ( + LimitingFactorEnumDepth LimitingFactorEnum = "depth" + + LimitingFactorEnumWidth LimitingFactorEnum = "width" + + LimitingFactorEnumCurveRadius LimitingFactorEnum = "curveRadius" +) + +type LosEnum string + +const ( + LosEnumNotAvailable LosEnum = "NotAvailable" + + LosEnumLOS1 LosEnum = "LOS1" + + LosEnumLOS2 LosEnum = "LOS2" + + LosEnumLOS3 LosEnum = "LOS3" +) + +type MaterialEnum string + +const ( + MaterialEnumGravel MaterialEnum = "Gravel" + + MaterialEnumRocky MaterialEnum = "Rocky" + + MaterialEnumStone MaterialEnum = "Stone" + + MaterialEnumAndesite MaterialEnum = "Andesite" + + MaterialEnumSleazyAndesite MaterialEnum = "SleazyAndesite" + + MaterialEnumSandyGravel MaterialEnum = "SandyGravel" + + MaterialEnumMarl MaterialEnum = "Marl" + + MaterialEnumSand MaterialEnum = "Sand" + + MaterialEnumSarmatianLimestone MaterialEnum = "SarmatianLimestone" + + MaterialEnumSandstonePeaks MaterialEnum = "SandstonePeaks" + + MaterialEnumRoughSandyGravel MaterialEnum = "RoughSandyGravel" +) + +type MeasureType string + +const ( + MeasureTypeMeasured MeasureType = "Measured" + + MeasureTypeForecasted MeasureType = "Forecasted" + + MeasureTypeMinimumGuaranteed MeasureType = "MinimumGuaranteed" +) + +type PositionEnum string + +const ( + PositionEnumRedBuoy PositionEnum = "RedBuoy" + + PositionEnumGreenBuoy PositionEnum = "GreenBuoy" + + PositionEnumRightBank PositionEnum = "RightBank" + + PositionEnumLeftBank PositionEnum = "LeftBank" + + PositionEnumMiddle PositionEnum = "Middle" + + PositionEnumAll PositionEnum = "All" +) + +type SurtypEnum string + +const ( + SurtypEnumMultibeam SurtypEnum = "Multibeam" + + SurtypEnumSinglebeam SurtypEnum = "Singlebeam" + + SurtypEnumADCP SurtypEnum = "ADCP" + + SurtypEnumInspectionTour SurtypEnum = "InspectionTour" +) + +type Error struct { + Detail string `xml:"detail,omitempty"` + + Error_code *ErrorCode `xml:"error_code,omitempty"` +} + +type ArrayOfMaterial struct { + Material []*MaterialEnum `xml:"Material,omitempty"` +} + +type ArrayOfKeyValuePair struct { + KeyValuePair []*KeyValuePair `xml:"KeyValuePair,omitempty"` +} + +type KeyValuePair struct { + Key string `xml:"Key,omitempty"` + + Value string `xml:"Value,omitempty"` +} + +type ArrayOfISRSPair struct { + ISRSPair []*ISRSPair `xml:"ISRSPair,omitempty"` +} + +type ISRSPair struct { + FromISRS string `xml:"fromISRS,omitempty"` + + ToISRS string `xml:"toISRS,omitempty"` +} + +type RequestedPeriod struct { + Date_start time.Time `xml:"Date_start,omitempty"` + + Date_end time.Time `xml:"Date_end,omitempty"` + + Value_interval int32 `xml:"Value_interval,omitempty"` +} + +type ArrayOfString struct { + String []string `xml:"http://www.ris.eu/wamos/common/3.0 string,omitempty"` +} + +type Char int32 + +type Duration *Duration + +type Guid string + +type IFairwayAvailabilityService interface { + + // Error can be either of the following types: + // + // - ErrorFault + + Get_bottleneck_fa(request *Get_bottleneck_fa) (*Get_bottleneck_faResponse, error) + + // Error can be either of the following types: + // + // - ErrorFault + + Get_stretch_fa(request *Get_stretch_fa) (*Get_stretch_faResponse, error) +} + +type FairwayAvailabilityService struct { + client *soap.SOAPClient +} + +func NewFairwayAvailabilityService(url string, tls bool, auth *soap.BasicAuth) *FairwayAvailabilityService { + if url == "" { + url = "" + } + client := soap.NewSOAPClient(url, tls, auth) + return &FairwayAvailabilityService{ + client: client, + } +} + +func NewFairwayAvailabilityServiceWithTLS(url string, tlsCfg *tls.Config, auth *soap.BasicAuth) *FairwayAvailabilityService { + if url == "" { + url = "" + } + client := soap.NewSOAPClientWithTLSConfig(url, tlsCfg, auth) + + return &FairwayAvailabilityService{ + client: client, + } +} + +func (service *FairwayAvailabilityService) Get_bottleneck_fa(request *Get_bottleneck_fa) (*Get_bottleneck_faResponse, error) { + response := new(Get_bottleneck_faResponse) + err := service.client.Call("http://www.ris.eu/fairwayavailability/3.0/IFairwayAvailabilityService/get_bottleneck_fa", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *FairwayAvailabilityService) Get_stretch_fa(request *Get_stretch_fa) (*Get_stretch_faResponse, error) { + response := new(Get_stretch_faResponse) + err := service.client.Call("http://www.ris.eu/fairwayavailability/3.0/IFairwayAvailabilityService/get_stretch_fa", request, response) + if err != nil { + return nil, err + } + + return response, nil +} diff -r 51a0ba4ede41 -r d8ca44615bfc schema/gemma.sql --- a/schema/gemma.sql Fri Dec 21 14:15:33 2018 +0100 +++ b/schema/gemma.sql Fri Dec 21 15:56:28 2018 +0100 @@ -139,9 +139,13 @@ ); CREATE TABLE levels_of_service ( - level_of_service smallint PRIMARY KEY + level_of_service smallint PRIMARY KEY, + name varchar(4) ); -INSERT INTO levels_of_service VALUES (1), (2), (3); +INSERT INTO levels_of_service ( + level_of_service, + name +) VALUES (1, 'LOS1'), (2, 'LOS2'), (3, 'LOS3'); CREATE TABLE riverbed_materials ( material varchar PRIMARY KEY