diff --git a/configuration/archiveDb.sh b/configuration/archiveDb.sh index 0bbf2fab872..1e5c05d744d 100755 --- a/configuration/archiveDb.sh +++ b/configuration/archiveDb.sh @@ -4,13 +4,22 @@ # command # Usage: archiveDb.sh +if [ "$1" = "-y" ]; then + CONFIRMATION="y" + shift +else + CONFIRMATION="" +fi + DB=$1 DUMPBASEDIR=/var/lib/mongodb -echo -n "This will drop the database $DB in the archive DB before importing. Are you sure (y/n)? " -read CONFIRMATION -if [ "$CONFIRMATION" != "y" ]; then - exit 2; +if [ "$CONFIRMATION" = "" ]; then + echo -n "This will drop the database $DB in the archive DB before importing. Are you sure (y/n)? " + read CONFIRMATION + if [ "$CONFIRMATION" != "y" ]; then + exit 2; + fi fi cd "$DUMPBASEDIR" diff --git a/home.md b/home.md index 3488eda6d98..5217eef99ab 100644 --- a/home.md +++ b/home.md @@ -140,6 +140,7 @@ SAP is at the center of today’s technology revolution, developing innovations ## Projects * [[Analytics on a stick|wiki/projects/analytics-on-a-stick]] +* [[Consolidating User Stores (bug 4006 / 4018)|wiki/projects/consolidating-user-stores]] ## Events and Planning * [[Project Planning (bigger development)|wiki/events/planning]] diff --git a/ios/SAPTracker/src/xcode/SAPTracker/zh.lproj/InfoPlist.strings b/ios/SAPTracker/src/xcode/SAPTracker/zh.lproj/InfoPlist.strings index 9400d9ad5c3..a36d498441e 100644 --- a/ios/SAPTracker/src/xcode/SAPTracker/zh.lproj/InfoPlist.strings +++ b/ios/SAPTracker/src/xcode/SAPTracker/zh.lproj/InfoPlist.strings @@ -1,8 +1,4 @@ -/* InfoPlist.strings - SAPTracker - - Created by Raimund Wege on 04.11.16. - Copyright © 2016 com.sap.sailing. All rights reserved. */ +/* InfoPlist.strings\n SAPTracker\n \n Created by Raimund Wege on 04.11.16.\n Copyright © 2016 com.sap.sailing. All rights reserved. */ "NSLocationAlwaysUsageDescription" = "为了跟踪整轮比赛,手机还需要在关闭或锁定屏幕以节省电量并避免无意中停止跟踪流程时继续跟踪。"; "NSLocationWhenInUseUsageDescription" = "为了跟踪整轮比赛,手机还需要在关闭或锁定屏幕以节省电量并避免无意中停止跟踪流程时继续跟踪。"; diff --git a/ios/SAPTracker/src/xcode/SAPTracker/zh.lproj/Localizable.strings b/ios/SAPTracker/src/xcode/SAPTracker/zh.lproj/Localizable.strings index 1db0ae3f4a6..23e52d70005 100644 Binary files a/ios/SAPTracker/src/xcode/SAPTracker/zh.lproj/Localizable.strings and b/ios/SAPTracker/src/xcode/SAPTracker/zh.lproj/Localizable.strings differ diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/storebadges/PlayStoreBadge.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/storebadges/PlayStoreBadge.java index 1a916016f90..9a2d432d91c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/storebadges/PlayStoreBadge.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/storebadges/PlayStoreBadge.java @@ -1,5 +1,6 @@ package com.sap.sailing.gwt.home.shared.partials.storebadges; +import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.safehtml.shared.SafeUri; import com.google.gwt.safehtml.shared.UriUtils; import com.google.gwt.uibinder.client.UiConstructor; @@ -17,6 +18,8 @@ public class PlayStoreBadge extends AbstractStoreBadge { @UiConstructor public PlayStoreBadge(String targetUrl) { super(targetUrl); + badgeImageUi.getStyle().setHeight(90, Unit.PX); + badgeImageUi.getStyle().setMargin(-15, Unit.PX); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractBoatCertificatesPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractBoatCertificatesPanel.java index 3602854a90e..a45b486f871 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractBoatCertificatesPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractBoatCertificatesPanel.java @@ -178,11 +178,11 @@ public abstract class AbstractBoatCertificatesPanel extends SimplePanel { contextUpdatePermissionCheck, this::suggestCertificates); suggestCertificatesButton.ensureDebugId("SuggestCertificatesButton"); // TABLE - Boats - CaptionPanel boatCaptionPanel = new CaptionPanel("Boats"); + CaptionPanel boatCaptionPanel = new CaptionPanel(stringMessages.boats()); boatCaptionPanel.add(boatTable); tablesPanel.setWidget(0, 0, boatCaptionPanel); // TABLE - Certificates - CaptionPanel certificatesCaptionPanel = new CaptionPanel("Certificates"); + CaptionPanel certificatesCaptionPanel = new CaptionPanel(stringMessages.certificates()); certificatesCaptionPanel.add(certificateTable); wireSelectionModels(); tablesPanel.setWidget(0, 1, certificatesCaptionPanel); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index bc4ae96c4e4..9ed19a35e83 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -2330,6 +2330,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String orcPerformanceCurveLegTypeDescriptionWindwardLeeward(); String orcPerformanceCurveLegTypeDescriptionWindwardLeewardRealLive(); String errorWhileLoadingUserSettings(String errorMessage); + String certificates(); String courseCreation(); String filterMarkTemplateByName(); String markTemplates(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 7c0d83ccb78..6628c349a5f 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -2333,6 +2333,7 @@ orcPerformanceCurveLegTypeDescriptionConstructedCourse=Constructed course; each orcPerformanceCurveLegTypeDescriptionWindwardLeeward=Windward/Leeward (up and down) is a conventional course around windward and leeward marks where the race course consists of 50% upwind and 50% downwind legs.\nDuring the race the actual leg type (upwind/downwind) will be ignored by the calculations. orcPerformanceCurveLegTypeDescriptionWindwardLeewardRealLive=Windward/Leeward (up and down) is a conventional course around windward and leeward marks where the race course consists of 50% upwind and 50% downwind legs.\nDuring the race, upwind and downwind legs will automatically be modeled as respective "constructed course" legs for better predictions, whereas after the race the averaged values will apply for all legs. errorWhileLoadingUserSettings=Error while loading user settings: {0} +certificates=Certificates courseCreation=Course Creation filterMarkTemplateByName=Filter mark templates markTemplates=Mark Templates diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index ab4d6c290bd..f0f7567b16d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -2268,10 +2268,10 @@ startProcedure=Startverfahren startMode=Startmodus gateOpeningTime=Torstart Öffnungsdauer protestTimeInMinutes=Protestzeit in Minuten -updateCertificates=Bearbeiten der ORC Zertifikate für Teilnehmer/Boote +updateCertificates=Bearbeiten der ORC Messbriefe für Teilnehmer/Boote actionDefineLegForOrcPcs=Bahnschenkel-Eigenschaften für ORC Performance Curve-Wertung festlegen actionDefineAllLegsForOrcPcs=Eigenschaften für alle Bahnschenkel für ORC Performance Curve-Wertung gemeinsam festlegen -importCertificates=Zertifikate importieren +importCertificates=Messbriefe importieren assignCertificates=Zertikate zuweisen orcPerformanceCurveLeg=ORC Performance Curve Bahnschenkel orcPerformanceCurveLeg=ORC Performance Curve Bahnschenkel @@ -2281,16 +2281,16 @@ distanceInNauticalMiles=Distanz in Seemeilen legTwaInDegrees=TWA in Grad pleaseEnterADistance=Bitte eine Distanz angeben pleaseEnterATwa=Bitte einen Wert für den TWA angeben -enterURLsForCertificateDownload=URLs zum Herunterladen von ORC-Zertifikaten eingeben -reallyChangeAssignedCertificateForBoat=Soll wirklich die Zuordnung des Zertifikats für Boot {0} verändert werden? -certificateURLs=URLs für Zertifikats-Download -errorObtainingCertificates=Fehler beim Laden der Zertifikate: {0} -errorAssigningCertificatesToBoats=Fehler beim Zuordnen der Zertifikate für die folgenden Boote: {0} -filterCertificates=Zertifikate filtern nach Segelnummer, Bootsname, ... +enterURLsForCertificateDownload=URLs zum Herunterladen von ORC-Messbriefen eingeben +reallyChangeAssignedCertificateForBoat=Soll wirklich die Zuordnung des Messbriefs für Boot {0} verändert werden? +certificateURLs=URLs für Messbrief-Download +errorObtainingCertificates=Fehler beim Laden der Messbriefe: {0} +errorAssigningCertificatesToBoats=Fehler beim Zuordnen der Messbriefe für die folgenden Boote: {0} +filterCertificates=Messbriefe filtern nach Segelnummer, Bootsname, ... errorUnableToGetBoatsForRegatta=Fehler beim Laden der Boote für Regatta {0}: {1} certificateIssuingDate=Ausgestellt -errorAssigningCertificates: Fehler beim Zuweisen von Zertifikaten zu Booten: {0} -insertedAndReplacedAndRemovedCertificateAssignments=Neue Zertifikatszuweisungen: {0}. Geänderte Zuweisungen: {1}. Gelöschte Zuweisungen: {2}. +errorAssigningCertificates: Fehler beim Zuweisen von Messbriefen zu Booten: {0} +insertedAndReplacedAndRemovedCertificateAssignments=Neue Messbriefzuweisungen: {0}. Geänderte Zuweisungen: {1}. Gelöschte Zuweisungen: {2}. spreadTotalDistanceProportionallyAcrossLegs=Gesamtdistanz proportional auf Bahnschenkel verteilen trackedTwaInDegrees=Getrackter TWA (°) trackedDistanceInNauticalMiles=Getrackte Schenkel-Distanz (NM) @@ -2313,14 +2313,14 @@ ownMaxImpliedWind=Maximalen implizierten Wind aus dem Rennen selbst verwenden useImpliedWindFromOtherRace=Implizierten Wind eines anderen Rennens verwenden pleaseProvideAFixedValueForImpliedWindSpeed=Bitte einen festen Wert für die zu verwendende implizierte Windgeschwindigkeit angeben. pleaseSelectARaceWhoseImpliedWindToUse=Bitte ein anderes Rennen auswählen, dessen implizierter Wind hier verwendet werden soll. -suggestCertificatesForSelectedBoats=Zertifikate von ORC Website für ausgewählte Boote vorschlagen -errorSuggestingCertificates=Fehler beim Abfragen von passenden Zertifikaten von der ORC Website: {0} -searchForCertificatesExplanation=Nach Zertifikaten nach einem oder mehreren Kriterien suchen. "%" als Maskenzeichen ("Wildcard", "Joker") bei Yachtname, Segelnummer und Bootsklasse verwenden. +suggestCertificatesForSelectedBoats=Messbriefe von ORC Website für ausgewählte Boote vorschlagen +errorSuggestingCertificates=Fehler beim Abfragen von passenden Messbriefen von der ORC Website: {0} +searchForCertificatesExplanation=Nach Messbriefen nach einem oder mehreren Kriterien suchen. "%" als Maskenzeichen ("Wildcard", "Joker") bei Yachtname, Segelnummer und Bootsklasse verwenden. issuingCountry=Ausstellendes Land yearOfIssuance=Ausstellungsjahr referenceNumber=Referenznummer yachtName=Name der Yacht -errorSearchingForCertificates=Fehler bei der Suche nach ORC-Zertifikaten: {0} +errorSearchingForCertificates=Fehler bei der Suche nach ORC-Messbriefen: {0} orcPerformanceCurveLegTypeDescriptionCircularRandom=Circular Random ist ein hypothetischer Kurstyp, bei dem das Boot eine kreisförmige Insel umsegelt, während die Richtung des wahren Windes konstant bleibt. orcPerformanceCurveLegTypeDescriptionLongDistance=Coastal / Long Distance ist ein zusammensetzter Kurs, der progressiv mit dem Winkel des wahren Windes variiert. orcPerformanceCurveLegTypeDescriptionNonSpinnaker=Non Spinnaker verhält sich wie "Circular Random", wobei ohne die Verwendung eines Spinnakers gerechnet wird. @@ -2347,7 +2347,8 @@ milliBarUnits=mbar manage2SailEventIdBox=Manage2Sail Event ID manage2SailEventURLBox=Manage2Sail Event URL (json) orcPerformanceCurveLegs=ORC Performance Curve Bahnschenkel -errorAssigningCertificates=Beim Zuweisen von Zerfikaten zu Booten ist ein Fehler aufgetreten: {0} +errorAssigningCertificates=Beim Zuweisen von Messbriefen zu Booten ist ein Fehler aufgetreten: {0} +certificates=Messbriefe courseCreation=Kurserstellung filterMarkTemplateByName=Bahnmarkenvorlagen filter markTemplates=Bahnmarkenvorlagen diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_es.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_es.properties index 1cf9a423d68..76a7df1a58f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_es.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_es.properties @@ -2301,3 +2301,29 @@ selectScratchBoat=Seleccionar embarcación scratch errorObtainingScratchBoat=Error al obtener la embarcación scratch: {0} errorSettingScratchBoat=Error al fijar la embarcación scratch: {0} scratchBoatSetSuccessfully=Embarcación scratch fijada correctamente +setImpliedWind=Fijar viento implícito +impliedWindSource=Fuente de viento implícito +provideImpliedWindSourceForRace=Indicar fuente de viento implícito para carrera {0} +errorObtainingImpliedWindSourceForRace=Error al obtener fuente de viento implícito para carrera {0}: {1} +errorSettingImpliedWindSourceForRace=Error al fijar fuente de viento implícito para carrera {0}: {1} +impliedWindForRaceSetSuccessfully=Fuente de viento implícito para carrera {0} fijada correctamente. +fixedImpliedWindInKnots=Fijar viento implícito fijado (kts) +ownMaxImpliedWind=Utilizar viento implícito máximo propio de carrera. +useImpliedWindFromOtherRace=Utilizar otro viento implícito de carrera +pleaseProvideAFixedValueForImpliedWindSpeed=Indique un valor fijo válido para la velocidad de viento implícito en nudos. +pleaseSelectARaceWhoseImpliedWindToUse=Seleccione una carrera cuyo viento implícito a utilizar. +suggestCertificatesForSelectedBoats=Sugiera certificados de la página web de ORC para embarcaciones seleccionadas +errorSuggestingCertificates=Error que sugiere certificados ORC: {0} +searchForCertificatesExplanation=Busque certificados por uno o más criterios. Utilice "%" como carácter comodín en los campos de búsqueda de nombre del yate, número de vela y clase de embarcación. +issuingCountry=País emisor +yearOfIssuance=Año de emisión +referenceNumber=Número de referencia +yachtName=Nombre de yate +errorSearchingForCertificates=Búsqueda de error para certificado de ORC: {0} +orcPerformanceCurveLegTypeDescriptionCircularRandom=Regata de navegación circular aleatoria es un tipo de regata hipotética en la que la embarcación circunnavega una isla circular con la constante mantenida de dirección de viento real. +orcPerformanceCurveLegTypeDescriptionLongDistance=Regata costera/de altura es una regata compuesta, cuyo contenido varía progresivamente con el ángulo de viento real. +orcPerformanceCurveLegTypeDescriptionNonSpinnaker=No spinnaker es un tipo de regata aleatoria circular pero calculada sin utilizar un spinnaker. +orcPerformanceCurveLegTypeDescriptionConstructedCourse=Regata construida; cada margen de tramo viene determinado por su tramo y su ángulo de viento real. +orcPerformanceCurveLegTypeDescriptionWindwardLeeward=Regata de barlovento/sotavento (arriba y abajo) es una regata convencional alrededor de marcas de barlovento y sotavento donde la regata de carrera consiste en tramos de 50% de viento a barlovento y 50% de viento a sotavento.\nDurante la carrera, los cálculos ignoran el tipo de tramo real (barlovento/sotavento). +orcPerformanceCurveLegTypeDescriptionWindwardLeewardRealLive=Regata de barlovento/sotavento (arriba y abajo) es una regata convencional alrededor de marcas de barlovento y sotavento donde la regata de carrera consiste en tramos de 50% de viento a barlovento y 50% de viento a sotavento.\nDurante la carrera, los tramos de barlovento y sotavento se modelan automáticamente como tramos de "regatas construidas" respectivamente para mejores predicciones, mientras que tras la carrera los valores medios se aplicarán a todos los tramos. +errorWhileLoadingUserSettings=Error al cargar las opciones de usuario: {0} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_fr.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_fr.properties index 08abe3e1ea4..43eefab329c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_fr.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_fr.properties @@ -2301,3 +2301,29 @@ selectScratchBoat=Sélectionner bateau Scratch errorObtainingScratchBoat=Erreur lors de l''accès au bateau Scratch : {0} errorSettingScratchBoat=Erreur lors de la définition du bateau Scratch : {0} scratchBoatSetSuccessfully=Bateau Scratch défini correctement +setImpliedWind=Définir le vent implicite +impliedWindSource=Source du vent implicite +provideImpliedWindSourceForRace=Indiquer la source du vent implicite pour la course {0} +errorObtainingImpliedWindSourceForRace=Erreur lors de l''accès à la source du vent implicite pour la course {0} : {1} +errorSettingImpliedWindSourceForRace=Erreur lors de la définition de la source du vent implicite pour la course {0} : {1} +impliedWindForRaceSetSuccessfully=La source du vent implicite pour la course {0} a été correctement définie. +fixedImpliedWindInKnots=Définir le vent implicite fixe (nds) +ownMaxImpliedWind=Utiliser le vent implicite maximal propre à la course +useImpliedWindFromOtherRace=Utiliser le vent implicite d''une autre course +pleaseProvideAFixedValueForImpliedWindSpeed=Veuillez indiquer une valeur fixe valide pour le vent implicite (en nœuds). +pleaseSelectARaceWhoseImpliedWindToUse=Veuillez sélectionner une course dont vous souhaitez utiliser le vent implicite. +suggestCertificatesForSelectedBoats=Suggérer des certificats du site Web ORC pour les bateaux sélectionnés +errorSuggestingCertificates=Erreur lors de la suggestion de certificats ORC : {0} +searchForCertificatesExplanation=Recherchez des certificats à l''aide d''un ou plusieurs critères. Utilisez "%" comme caractère générique dans le nom du voilier, le numéro de la voile et les zones de recherche de classes de bateaux. +issuingCountry=Pays délivreur +yearOfIssuance=Année de délivrance +referenceNumber=Numéro de référence +yachtName=Nom du voilier +errorSearchingForCertificates=Erreur de recherche de certificat ORC : {0} +orcPerformanceCurveLegTypeDescriptionCircularRandom="Circular Random" (circulaire aléatoire) est un type de parcours hypothétique dans lequel le bateau fait le tour d’une île circulaire avec la direction du vent réel maintenue constante. +orcPerformanceCurveLegTypeDescriptionLongDistance="Coastal / Long Distance" (côtier / longue distance) est un parcours composite dont le contenu varie progressivement avec l’angle du vent réel. +orcPerformanceCurveLegTypeDescriptionNonSpinnaker="Non Spinnaker" est un parcours de type "Circular Random", mais calculé sans utilisation de spinnaker. +orcPerformanceCurveLegTypeDescriptionConstructedCourse=Parcours construit. La compensation de chaque portion de parcours est déterminée en fonction de sa longueur et de l''angle du vent réel. +orcPerformanceCurveLegTypeDescriptionWindwardLeeward="Windward/Leeward" (au vent et sous le vent) est un parcours conventionnel autour des marques Au vent et Sous le vent où le parcours de la course se compose de portions de parcours à 50 % dans le lit du vent et à 50 % avec vent arrière.\nPendant la course, le type de portion de parcours réel (dans le lit du vent/vent arrière) ne sera pas pris en compte par les calculs. +orcPerformanceCurveLegTypeDescriptionWindwardLeewardRealLive="Windward/Leeward" (au vent et sous le vent) est un parcours conventionnel autour des marques Au vent et Sous le vent où le parcours de la course se compose de portions de parcours à 50 % dans le lit du vent et à 50 % avec vent arrière.\nPendant la course, les portions de parcours dans le lit du vent et avec vent arrière seront automatiquement modélisées respectivement comme portions de parcours de "course construite" afin d''obtenir de meilleures prévisions, alors qu''après la course, les valeurs moyennes s''appliqueront à toutes les portions de parcours. +errorWhileLoadingUserSettings=Erreur lors du chargement des options utilisateur : {0} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_it.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_it.properties index 39248ecfa6e..a7e4848d5c2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_it.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_it.properties @@ -2301,3 +2301,29 @@ selectScratchBoat=Seleziona una barca di riferimento errorObtainingScratchBoat=Errore durante l''ottenimento della barca di riferimento: {0} errorSettingScratchBoat=Errore durante l''impostazione della barca di riferimento: {0} scratchBoatSetSuccessfully=Barca di riferimento impostata correttamente. +setImpliedWind=Imposta vento implicito +impliedWindSource=Origine vento implicito +provideImpliedWindSourceForRace=Indica origine vento implicito per gara {0} +errorObtainingImpliedWindSourceForRace=Errore nell''ottenimento dell''origine vento implicito per gara {0}: {1} +errorSettingImpliedWindSourceForRace=Errore di impostazione dell''origine vento implicito per gara {0}: {1} +impliedWindForRaceSetSuccessfully=Origine vento implicito per gara {0} impostata correttamente. +fixedImpliedWindInKnots=Imposta vento implicito fisso (nodi) +ownMaxImpliedWind=Utilizza vento implicito massimo proprio della gara +useImpliedWindFromOtherRace=Utilizza vento implicito di altra gara +pleaseProvideAFixedValueForImpliedWindSpeed=Indica un valore fisso valido per la velocità del vento implicito in nodi. +pleaseSelectARaceWhoseImpliedWindToUse=Seleziona una gara di cui utilizzare il vento implicito. +suggestCertificatesForSelectedBoats=Consiglia certificati dal sito web ORC per le barche selezionate +errorSuggestingCertificates=Errore nel consiglio dei certificati ORC: {0} +searchForCertificatesExplanation=Cerca certificati in base a uno o più criteri. Utilizza "%" come carattere per ricerca generica nei campi di ricerca nome dello yacht, numero vela e classe barca. +issuingCountry=Paese emittente +yearOfIssuance=Anno di emissione +referenceNumber=Numero di riferimento +yachtName=Nome dello yacht +errorSearchingForCertificates=Errore di ricerca per certificato ORC: {0} +orcPerformanceCurveLegTypeDescriptionCircularRandom=Circular Random è un tipo di rotta ipotetico in cui la barca circumnaviga un''isola circolare con direzione del vento costante. +orcPerformanceCurveLegTypeDescriptionLongDistance=Coastal / Long Distance è una rotta composta il cui contenuto varia progressivamente con l''angolo del vento reale. +orcPerformanceCurveLegTypeDescriptionNonSpinnaker=Non Spinnaker è un tipo di rotta random circolare calcolato senza utilizzare uno spinnaker. +orcPerformanceCurveLegTypeDescriptionConstructedCourse=Rotta costruita; il compenso di ogni tratta è determinato dalla relativa lunghezza e dall''angolo del vento reale. +orcPerformanceCurveLegTypeDescriptionWindwardLeeward=Distanza sopravento/sottovento è una rotta convenzionale intorno a segnali di distanza sopravento/sottovento che consiste di tratte 50% sopravento e 50% sottovento.\nDurante la gara i calcoli non terranno conto del tipo di tratta effettivo (sopravento/sottovento). +orcPerformanceCurveLegTypeDescriptionWindwardLeewardRealLive=Distanza sopravento/sottovento è una rotta convenzionale intorno a segnali di distanza sopravento/sottovento che consiste di tratte 50% sopravento e 50% sottovento.\nDurante la gara, le tratte sopravento e sottovento vengono modellate come rispettive tratte con "rotta costruita" per migliori previsioni, mentre dopo la gara i valori medi saranno applicati a tutte le tratte. +errorWhileLoadingUserSettings=Errore durante il caricamento delle impostazioni utente: {0} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties index f14b6c9878f..9cf5086812c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties @@ -1406,12 +1406,12 @@ rankingMetric=ランキング oneDesignRankingMetric=ワンデザイン orcPerformanceCurveRankingMetric=ORC 性能曲線 (>=2015) orcPerformanceCurveLeaderForBaselineRankingMetric=ORC 性能曲線 (>=2015、首位艇が基準) -orcPerformanceCurveByImpliedWindRankingMetric=個別平均風速を伴う ORC 性能曲線 (<2015) +orcPerformanceCurveByImpliedWindRankingMetric=個別の平均風速 (Implied Wind) を伴う ORC 性能曲線 (<2015) timeOnTimeAndDistanceRankingMetric=Time on Time/Time on Distance oneDesignRankingMetricDescription=ワンデザイン: ラインを最初に通過した艇が勝者、\nウィンワード位置 (アップウィンド/ダウンウィンド) またはアロングコース位置 (リーチング) に基づくレース内ランク -orcPerformanceCurveRankingMetricDescription=ORC 性能曲線: 風に対して事前定義したレグのアングルを仮定して VPP/ポーラーに基づいて修正時間を与える洗練されたハンディキャップ付与方式です。\n平均風速 (implied wind) の値が最大の艇が判定されます。その他の艇はすべて、この最大平均風速を各艇の性能曲線にマッピングし、その平均風速に対する修正時間を決定してから、\n経過時間へのデルタを算出することによってランキングされます。合計計算時間は、GPH (General Purpose Handicap) 値が最も小さい艇の経過時間を基準に使用して算出されます。 -orcPerformanceCurveByImpliedWindRankingMetricDescription=ORC 性能曲線: 風に対して事前定義したレグのアングルを仮定して VPP/ポーラーに基づいて修正時間を与える洗練されたハンディキャップ付与方式です。\nこれらの修正時間に基づいて、ランキングの基礎となる "平均風速 (implied wind)" が計算されます。\n平均風速は、レース中にいつでも算出でき、したがってレース中ランキングの基礎となります。 -orcPerformanceCurveLeaderForBaselineRankingMetricDescription=ORC 性能曲線: 風に対して事前定義したレグのアングルを仮定して VPP/ポーラーに基づいて修正時間を与える洗練されたハンディキャップ付与方式です。\n平均風速 (implied wind) の値が最大の艇が判定されます。その他の艇はすべて、この最大平均風速を各艇の性能曲線にマッピングし、その平均風速に対する修正時間を決定してから、\n経過時間へのデルタを算出することによってランキングされます。修正時間の基準は、相対的な修正時間が最も小さい艇です。 +orcPerformanceCurveRankingMetricDescription=ORC 性能曲線: 風に対して事前定義したレグのアングルを仮定して VPP/ポーラーに基づいて修正時間を与える洗練されたハンディキャップ付与方式です。\n平均風速 (Implied Wind) の値が最大の艇が判定されます。その他の艇はすべて、この最大平均風速を各艇の性能曲線にマッピングし、その平均風速に対する修正時間を決定してから、\n経過時間へのデルタを算出することによってランキングされます。合計計算時間は、GPH (General Purpose Handicap) 値が最も小さい艇の経過時間を基準に使用して算出されます。 +orcPerformanceCurveByImpliedWindRankingMetricDescription=ORC 性能曲線: 風に対して事前定義したレグのアングルを仮定して VPP/ポーラーに基づいて修正時間を与える洗練されたハンディキャップ付与方式です。\nこれらの修正時間に基づいて、ランキングの基礎となる "平均風速 (Implied Wind)" が計算されます。\n平均風速は、レース中にいつでも算出でき、したがってレース中ランキングの基礎となります。 +orcPerformanceCurveLeaderForBaselineRankingMetricDescription=ORC 性能曲線: 風に対して事前定義したレグのアングルを仮定して VPP/ポーラーに基づいて修正時間を与える洗練されたハンディキャップ付与方式です。\n平均風速 (Implied Wind) の値が最大の艇が判定されます。その他の艇はすべて、この最大平均風速を各艇の性能曲線にマッピングし、その平均風速に対する修正時間を決定してから、\n経過時間へのデルタを算出することによってランキングされます。修正時間の基準は、相対的な修正時間が最も小さい艇です。 timeOnTimeAndDistanceRankingMetricDescription=Time on Time / Time on Distance: 計算された時間による最終ランキングです。\n時間は実際の時間にオプションで係数 (初期値は 1.0) を適用して、\nコース長に適用される、海里当りの修正時間 (秒単位) を\n減じて計算されます。\nレース中のランクは、現在のレグの平均 VMG/VMC を仮定して\n最速艇の現在の位置への到着の予想に基づきます。 timeOnTimeFactor=ToT 係数 timeOnDistanceAllowanceInSecondsPerNauticalMile=ToD 修正時間 @@ -2301,3 +2301,29 @@ selectScratchBoat=最速艇の選択 errorObtainingScratchBoat=最速艇の取得でエラーが発生: {0} errorSettingScratchBoat=最速艇の設定でエラーが発生: {0} scratchBoatSetSuccessfully=最速艇が設定されました +setImpliedWind=平均風速 (Implied Wind) を設定 +impliedWindSource=平均風速 (Implied Wind) の出所 +provideImpliedWindSourceForRace=レース {0} の平均風速 (Implied Wind) の出所を指定 +errorObtainingImpliedWindSourceForRace=レース {0} の平均風速 (Implied Wind) の出所の取得でエラーが発生: {1} +errorSettingImpliedWindSourceForRace=レース {0} の平均風速 (Implied Wind) の出所の設定でエラーが発生: {1} +impliedWindForRaceSetSuccessfully=レース {0} の平均風速 (Implied Wind) の出所が設定されました。 +fixedImpliedWindInKnots=固定の平均風速 (Implied Wind)を設定 (knt) +ownMaxImpliedWind=レース独自の最大の平均風速 (Implied Wind) を使用 +useImpliedWindFromOtherRace=他のレースの平均風速 (Implied Wind) を使用 +pleaseProvideAFixedValueForImpliedWindSpeed=平均風速 (Implied Wind) の有効な固定値を knt 単位で指定してください。 +pleaseSelectARaceWhoseImpliedWindToUse=使用する平均風速 (Implied Wind) の出所となるレースを選択してください。 +suggestCertificatesForSelectedBoats=選択した艇について ORC の Web サイトから証書を提案 +errorSuggestingCertificates=ORC 証書の提案でエラーが発生: {0} +searchForCertificatesExplanation=1 つ以上の基準で証書を検索します。ヨット名、セールナンバー、および艇種の検索項目では "%" をワイルドカード文字として使用します。 +issuingCountry=発行国 +yearOfIssuance=発行年 +referenceNumber=参照番号 +yachtName=ヨット名 +errorSearchingForCertificates=ORC 証書の検索でエラーが発生: {0} +orcPerformanceCurveLegTypeDescriptionCircularRandom=Circular Random (サーキュラーランダム) は、一定に保たれた真風向で円形の島を艇が周航する仮想コースのタイプです。 +orcPerformanceCurveLegTypeDescriptionLongDistance=Coastal / Long Distance (沿岸/長距離) は、複合コースであり、その内容が真風角度によって漸進的に変化します。 +orcPerformanceCurveLegTypeDescriptionNonSpinnaker=Non Spinnaker (ノンスピネーカー) は、Circular Random と同じコースタイプですが、スピネーカーの使用なしで計算されます。 +orcPerformanceCurveLegTypeDescriptionConstructedCourse=Constructed (コンストラクテッド) コースでは、各レグの修正時間は、その長さと真風角度によって決定されます。 +orcPerformanceCurveLegTypeDescriptionWindwardLeeward=Windward/Leeward (風上と風下) は、レースコースが 50% の風上レグと 50% の風下レグから構成される、風上および風下マークを周回する一般的なコースです。\nレース中は、実際のレグタイプ (風上/風下) は計算では無視されます。 +orcPerformanceCurveLegTypeDescriptionWindwardLeewardRealLive=Windward/Leeward (風上と風下) は、レースコースが 50% の風上レグと 50% の風下レグから構成される、風上および風下マークを周回する一般的なコースです。\nレース中は、風上レグと風下レグは予測をより良いものとするため、それぞれの "Constructed コース" レグとして自動的にモデル化され、一方、レース後は平均した値がすべてのレグに適用されます。 +errorWhileLoadingUserSettings=ユーザ設定のロード中にエラーが発生: {0} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_pt.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_pt.properties index d1e9f018c31..ce40cbbcbb1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_pt.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_pt.properties @@ -2301,3 +2301,29 @@ selectScratchBoat=Selecionar barco scratch errorObtainingScratchBoat=Erro ao obter barco scratch: {0} errorSettingScratchBoat=Erro ao definir barco scratch: {0} scratchBoatSetSuccessfully=Barco scratch definido com êxito. +setImpliedWind=Definir vento aproximado +impliedWindSource=Origem do vento aproximado +provideImpliedWindSourceForRace=Fornecer origem do vento aproximado para corrida {0} +errorObtainingImpliedWindSourceForRace=Erro ao obter a origem do vento aproximado para a corrida {0}: {1} +errorSettingImpliedWindSourceForRace=Erro ao definir a origem do vento aproximado para a corrida {0}: {1} +impliedWindForRaceSetSuccessfully=Origem do vento aproximado para corrida {0} definido com êxito. +fixedImpliedWindInKnots=Definir vento aproximado fixo (nós) +ownMaxImpliedWind=Utilizar vento aproximado máximo da própria corrida +useImpliedWindFromOtherRace=Utilizar vento aproximado de outra corrida +pleaseProvideAFixedValueForImpliedWindSpeed=Fornecer um valor fixo válido para a velocidade do vento aproximado em nós. +pleaseSelectARaceWhoseImpliedWindToUse=Selecione uma corrida da qual deve ser utilizado o vento aproximado. +suggestCertificatesForSelectedBoats=Sugerir certificados do site ORC para barcos selecionados +errorSuggestingCertificates=Erro ao sugerir certificados OCR: {0} +searchForCertificatesExplanation=Procurar certificados por um ou mais critérios. Utilize "%" como caractere genérico nos campos de pesquisa do nome do iate, número da vela e classe de barcos. +issuingCountry=País emissor +yearOfIssuance=Ano da emissão +referenceNumber=Número de referência +yachtName=Nome do iate +errorSearchingForCertificates=Erro ao procurar certificado OCR: {0} +orcPerformanceCurveLegTypeDescriptionCircularRandom=Aleatório circular é um tipo de percurso hipotético no qual o barco circunavega uma ilha circular mantendo constante a direção do vento verdadeiro. +orcPerformanceCurveLegTypeDescriptionLongDistance=Costeiro/longa distância é um percurso composto, cujo conteúdo varia progressivamente com o ângulo do vento verdadeiro. +orcPerformanceCurveLegTypeDescriptionNonSpinnaker=Sem spinnaker é um tipo de percurso aleatório circular, mas calculado sem a utilização de um spinnaker. +orcPerformanceCurveLegTypeDescriptionConstructedCourse=Percurso construído; a bonificação de cada perna é determinada pelo respectivo comprimento e ângulo do vento verdadeiro. +orcPerformanceCurveLegTypeDescriptionWindwardLeeward=Barlavento/sotavento (contravento e popa) é um percurso convencional em volta de marcas de barlavento e sotavento, em que o percurso da corrida é composto por 50% de pernas de contravento e 50% de pernas de popa.\nDurante a corrida, o tipo de perna real (contravento/popa) será ignorado por todos os cálculos. +orcPerformanceCurveLegTypeDescriptionWindwardLeewardRealLive=Barlavento/sotavento (contravento e popa) é um percurso convencional em volta de marcas de barlavento e sotavento, em que o percurso da corrida é composto por 50% de pernas de contravento e 50% de pernas de popa.\nDurante a corrida, as pernas de contravento e de popa serão modeladas automaticamente como pernas de "percurso construído" respectivas para melhores previsões, enquanto que depois da corrida, os valores médios serão aplicados a todas as pernas. +errorWhileLoadingUserSettings=Erro ao carregar configurações do usuário: {0} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties index 391051f264d..f8ae0b89c7a 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties @@ -380,7 +380,7 @@ replicatingFromMaster=Репликация с главного экземпля showWindSpeedSeries=Показать данные о скорости ветра showWindDirectionSeries=Показать данные о направлениях ветра fleet=Флот -boatClass=Класс лодок +boatClass=Класс лодки setDelayToLive=Установить задержку оперативных данных pleaseEnterNonEmptyVenue=Введите место. pleaseEnterStartAndEndDate=Введите даты начала и окончания. @@ -1406,12 +1406,12 @@ rankingMetric=Ранг oneDesignRankingMetric=Монотип orcPerformanceCurveRankingMetric=Кривая эффективности ORC (>=2015) orcPerformanceCurveLeaderForBaselineRankingMetric=Кривая эффективности ORC (>=2015, лидер в качестве базовой линии) -orcPerformanceCurveByImpliedWindRankingMetric=Кривая эффективности ORC c учетом индивидуального подразумеваемого ветра (<2015) +orcPerformanceCurveByImpliedWindRankingMetric=Кривая эффективности ORC c учетом индивидуального предполагаемого ветра (<2015) timeOnTimeAndDistanceRankingMetric=Время-время/Время-дистанция oneDesignRankingMetricDescription=Монотип: первый пересекший линию побеждает;\nранги в гонке основаны на позиции к ветру (наветренная/подветренная) или позиции на курсе (полный ветер) -orcPerformanceCurveRankingMetricDescription=Кривая эффективности ORC: сложная схема гандикапа, предоставляющая фору с учетом VPP/полярных данных для предварительно определенных углов отрезков к ветру;\nнаибольшее значение подразумеваемого ветра определено; все лодки ранжируются путем сопоставления этого наибольшего подразумеваемого ветра с кривыми эффективности, определения допусков для подразумеваемого ветра\nи расчета дельты от прошедшего времени. Общее рассчитанное время вычисляется по прошедшему времени лодки с наибольшим GPH в качестве базовой линии. -orcPerformanceCurveByImpliedWindRankingMetricDescription=Кривая эффективности ORC: сложная схема гандикапа, предоставляющая фору с учетом VPP/полярных данных для предварительно определенных углов отрезков к ветру;\nна основе этих допусков рассчитывается "подразумеваемый ветер", используемый как основа для ранжирования.\nПодразумеваемый ветер можно рассчитать в любое время в ходе гонки, поэтому он является основой для ранжирования в гонке. -orcPerformanceCurveLeaderForBaselineRankingMetricDescription=Кривая эффективности ORC: сложная схема гандикапа, предоставляющая фору с учетом VPP/полярных данных для предварительно определенных углов отрезков к ветру;\nнаибольшее значение подразумеваемого ветра определено; все лодки ранжируются путем сопоставления этого наибольшего подразумеваемого ветра с кривыми эффективности, определения допусков для подразумеваемого ветра\nи расчета дельты от прошедшего времени. Базовой линией для скорректированного времени является лодка с наименьшим относительным скорректированным временем. +orcPerformanceCurveRankingMetricDescription=Кривая эффективности ORC: сложная схема гандикапа, предоставляющая фору с учетом VPP/полярных данных для предварительно определенных углов отрезков к ветру;\nнаибольшее значение предполагаемого ветра определено; все лодки ранжируются путем сопоставления этого наибольшего предполагаемого ветра с кривыми эффективности, определения допусков для предполагаемого ветра\nи расчета дельты от прошедшего времени. Общее рассчитанное время вычисляется по прошедшему времени лодки с наибольшим GPH в качестве базовой линии. +orcPerformanceCurveByImpliedWindRankingMetricDescription=Кривая эффективности ORC: сложная схема гандикапа, предоставляющая фору с учетом VPP/полярных данных для предварительно определенных углов отрезков к ветру;\nна основе этих допусков рассчитывается "предполагаемый ветер", используемый как основа для ранжирования.\nПредполагаемый ветер можно рассчитать в любое время в ходе гонки, поэтому он является основой для ранжирования в гонке. +orcPerformanceCurveLeaderForBaselineRankingMetricDescription=Кривая эффективности ORC: сложная схема гандикапа, предоставляющая фору с учетом VPP/полярных данных для предварительно определенных углов отрезков к ветру;\nнаибольшее значение предполагаемого ветра определено; все лодки ранжируются путем сопоставления этого наибольшего предполагаемого ветра с кривыми эффективности, определения допусков для предполагаемого ветра\nи расчета дельты от прошедшего времени. Базовой линией для скорректированного времени является лодка с наименьшим относительным скорректированным временем. timeOnTimeAndDistanceRankingMetricDescription=Время-время/Время-дистанция: окончательное ранжирование по расчетному времени;\nвремя рассчитывается путем необязательного применения коэффициента к фактическому времени (по умолчанию 1,0)\nи вычитания допуска в секундах на морскую милю\nк длине курса.\nРанги в гонке основаны на ожидаемом прибытии на текущую позицию самой быстрой лодки\nс учетом средних значений VMG/VMC текущего отрезка. timeOnTimeFactor=Фактор ToT timeOnDistanceAllowanceInSecondsPerNauticalMile=Допуск ToD @@ -2301,3 +2301,29 @@ selectScratchBoat=Выбрать отсчетную лодку errorObtainingScratchBoat=Ошибка вызова отсчетной лодки: {0} errorSettingScratchBoat=Ошибка настройки отсчетной лодки: {0} scratchBoatSetSuccessfully=Отсчетная лодка настроена. +setImpliedWind=Установить предполагаемый ветер +impliedWindSource=Источник предполагаемого ветра +provideImpliedWindSourceForRace=Предоставьте источник предполагаемого ветра для гонки {0} +errorObtainingImpliedWindSourceForRace=Ошибка при получении источника предполагаемого ветра для гонки {0}: {1} +errorSettingImpliedWindSourceForRace=Ошибка при установке источника предполагаемого ветра для гонки {0}: {1} +impliedWindForRaceSetSuccessfully=Источник предполагаемого ветра для гонки {0} установлен успешно. +fixedImpliedWindInKnots=Установить фиксированный предполагаемый ветер (уз) +ownMaxImpliedWind=Использовать собственный макс. предполагаемый ветер гонки +useImpliedWindFromOtherRace=Использовать предполагаемый ветер другой гонки +pleaseProvideAFixedValueForImpliedWindSpeed=Предоставьте допустимое фиксированное значение скорости предполагаемого ветра в узлах. +pleaseSelectARaceWhoseImpliedWindToUse=Выберите гонку, предполагаемый ветер которой следует использовать. +suggestCertificatesForSelectedBoats=Предлагать сертификаты с веб-сайта ORC для выбранных лодок +errorSuggestingCertificates=Ошибка при предложении сертификатов ORC: {0} +searchForCertificatesExplanation=Поиск сертификатов по одному или нескольким критериям. В качестве подстановочного знака в полях поиска "Название яхты", "Номер на парусе" и "Класс лодки" используйте "%". +issuingCountry=Страна выдачи +yearOfIssuance=Год выдачи +referenceNumber=Ссылочный номер +yachtName=Название яхты +errorSearchingForCertificates=Ошибка поиска сертификата ORC: {0} +orcPerformanceCurveLegTypeDescriptionCircularRandom=Случайный кружной: гипотетический тип курса, которым лодка обходит вокруг круглого острова при постоянном направлении истинного ветра. +orcPerformanceCurveLegTypeDescriptionLongDistance=Каботаж/дальнее следование: составной курс, изменчивость которого положительно коррелирует с углом истинного ветра. +orcPerformanceCurveLegTypeDescriptionNonSpinnaker=Без спиннакера: случайный кружной тип курса, рассчитываемый без использования спиннакера. +orcPerformanceCurveLegTypeDescriptionConstructedCourse=Конструируемый курс; допуск каждого отрезка определяется его длиной и углом истинного ветра. +orcPerformanceCurveLegTypeDescriptionWindwardLeeward=На ветре/под ветром (по ветру и против ветра): обычный курс вокруг наветренных и подветренных знаков, где курс гонки состоит из 50% наветренных и 50% подветренных отрезков.\nПри расчетах фактический тип отрезка (по ветру/против ветра) в ходе гонки будет игнорироваться. +orcPerformanceCurveLegTypeDescriptionWindwardLeewardRealLive=На ветре/под ветром (по ветру и против ветра): обычный курс вокруг наветренных и подветренных знаков, где курс гонки состоит из 50% наветренных и 50% подветренных отрезков.\nВ ходе гонки наветренные и подветренные отрезки будут автоматически моделироваться как соответствующие отрезки "конструируемого курса" для лучшего прогнозирования, а после гонки для всех этапов будут применяться усредненные значения. +errorWhileLoadingUserSettings=Ошибка при загрузке пользовательских настроек: {0} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties index 69b2c5a5195..adbc97586d6 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties @@ -2301,3 +2301,29 @@ selectScratchBoat=选择新手船只 errorObtainingScratchBoat=获得新手船只时出错:{0} errorSettingScratchBoat=设置新手船只时出错:{0} scratchBoatSetSuccessfully=新手船只已成功设置。 +setImpliedWind=设置隐藏式风 +impliedWindSource=隐藏式风源 +provideImpliedWindSourceForRace=为{0}竞赛提供隐藏式风源 +errorObtainingImpliedWindSourceForRace=获得{0}竞赛的隐藏式风源时发生错误:{1} +errorSettingImpliedWindSourceForRace=设置{0}竞赛的隐藏式风源时发生错误:{1} +impliedWindForRaceSetSuccessfully={0}竞赛的隐藏式风源已成功设置。 +fixedImpliedWindInKnots=设置固定的隐藏式风源 (kts) +ownMaxImpliedWind=使用竞赛自己的最大隐藏式风 +useImpliedWindFromOtherRace=使用其他竞赛的隐藏式风 +pleaseProvideAFixedValueForImpliedWindSpeed=请提供竞赛隐藏式风风速的有效固定值(节) +pleaseSelectARaceWhoseImpliedWindToUse=请选择使用其隐藏式风的竞赛。 +suggestCertificatesForSelectedBoats=从 ORC 网站为所选船只建议证书 +errorSuggestingCertificates=建议 ORC 证书时发生错误:{0} +searchForCertificatesExplanation=根据一个或多个条件搜索证书。使用 "%" 作为游艇名称、帆号和船只级别搜索字段中的通配符。 +issuingCountry=签发国家 +yearOfIssuance=签发年份 +referenceNumber=参考号 +yachtName=游艇名称 +errorSearchingForCertificates=搜索 ORC 证书错误:{0} +orcPerformanceCurveLegTypeDescriptionCircularRandom=环形随机是一种推测航向类型,船只以真实的风向保持常量环航圆形岛屿。 +orcPerformanceCurveLegTypeDescriptionLongDistance=沿海/长距离是复合航向,其内容逐渐随着真实风角的变化而变化。 +orcPerformanceCurveLegTypeDescriptionNonSpinnaker=非大三角帆是环形随机航向类型,但在没有使用三角帆的情况下计算。 +orcPerformanceCurveLegTypeDescriptionConstructedCourse=已构建的航向;每个航段的宽限由其长度和真实风角确定。 +orcPerformanceCurveLegTypeDescriptionWindwardLeeward=上风/下风(向上和向下)是围绕上风和下风标记的常规航向,其中,航向由 50% 上风和 50% 的下风航段构成。\n在竞赛期间,实际航段类型(上风/下风)会被计算忽略。 +orcPerformanceCurveLegTypeDescriptionWindwardLeewardRealLive=上风/下风(向上和向下)是围绕上风和下风标记的常规航向,其中,航向由 50% 上风和 50% 的下风航段构成。\n在竞赛期间,上风和下风航段会被自动视为各自的“已构建航向”以便获取更好的预测,而在竞赛之后,平均值将应用于所有航段。 +errorWhileLoadingUserSettings=加载用户设置时发生错误:{0} diff --git a/java/com.sap.sse.security.common/src/com/sap/sse/security/shared/PermissionChecker.java b/java/com.sap.sse.security.common/src/com/sap/sse/security/shared/PermissionChecker.java index 4db29dd091f..f1cbb80d795 100644 --- a/java/com.sap.sse.security.common/src/com/sap/sse/security/shared/PermissionChecker.java +++ b/java/com.sap.sse.security.common/src/com/sap/sse/security/shared/PermissionChecker.java @@ -307,7 +307,7 @@ public class PermissionChecker { final Set effectiveIdPartsToCheck; if (isIdPartWildcard) { effectiveIdPartsToCheck = Collections.singleton(""); - } else if(expandToSingleIds) { + } else if (expandToSingleIds) { effectiveIdPartsToCheck = idParts; } else { effectiveIdPartsToCheck = Collections.singleton(Util.joinStrings(WildcardPermission.SUBPART_DIVIDER_TOKEN, idParts)); @@ -334,12 +334,13 @@ public class PermissionChecker { } } } - - for (String actionPart : effectiveActionPartsToCheck) { - for (String idPart : effectiveIdPartsToCheck) { - String idSuffix = idPart.isEmpty() ? "" : WildcardPermission.PART_DIVIDER_TOKEN + idPart; - effectivePermissionsToCheck.add(new WildcardPermission( - typePart + WildcardPermission.PART_DIVIDER_TOKEN + actionPart + idSuffix)); + if (effectiveActionPartsToCheck != null) { + for (String actionPart : effectiveActionPartsToCheck) { + for (String idPart : effectiveIdPartsToCheck) { + String idSuffix = idPart.isEmpty() ? "" : WildcardPermission.PART_DIVIDER_TOKEN + idPart; + effectivePermissionsToCheck.add(new WildcardPermission( + typePart + WildcardPermission.PART_DIVIDER_TOKEN + actionPart + idSuffix)); + } } } } diff --git a/mobile/com.sap.sailing.android.buoy.positioning.app/res/values-zh-land/strings.xml b/mobile/com.sap.sailing.android.buoy.positioning.app/res/values-zh-land/strings.xml index 51f9842bf59..aa904ee86b9 100644 --- a/mobile/com.sap.sailing.android.buoy.positioning.app/res/values-zh-land/strings.xml +++ b/mobile/com.sap.sailing.android.buoy.positioning.app/res/values-zh-land/strings.xml @@ -1,4 +1,4 @@ - + "准确度" "距离" "GPS 位置" diff --git a/mobile/com.sap.sailing.android.buoy.positioning.app/res/values-zh/strings.xml b/mobile/com.sap.sailing.android.buoy.positioning.app/res/values-zh/strings.xml index 9ebb0977db6..e618637efbf 100644 --- a/mobile/com.sap.sailing.android.buoy.positioning.app/res/values-zh/strings.xml +++ b/mobile/com.sap.sailing.android.buoy.positioning.app/res/values-zh/strings.xml @@ -1,4 +1,4 @@ - + diff --git a/mobile/com.sap.sailing.android.shared/res/values-zh/strings.xml b/mobile/com.sap.sailing.android.shared/res/values-zh/strings.xml index 0449fc2ef14..bd5284c2183 100644 --- a/mobile/com.sap.sailing.android.shared/res/values-zh/strings.xml +++ b/mobile/com.sap.sailing.android.shared/res/values-zh/strings.xml @@ -1,4 +1,4 @@ - + diff --git a/mobile/com.sap.sailing.android.shared/res/values-zh/strings_fragment.xml b/mobile/com.sap.sailing.android.shared/res/values-zh/strings_fragment.xml index 67cc081834f..0f098a33b5b 100644 --- a/mobile/com.sap.sailing.android.shared/res/values-zh/strings_fragment.xml +++ b/mobile/com.sap.sailing.android.shared/res/values-zh/strings_fragment.xml @@ -1,4 +1,4 @@ - + "扫描二维码" "二维码可在确认参与时找到" "没有二维码?" diff --git a/mobile/com.sap.sailing.android.tracking.app/res/values-zh/preferences.xml b/mobile/com.sap.sailing.android.tracking.app/res/values-zh/preferences.xml index 904fae2353c..bfd699173a5 100644 --- a/mobile/com.sap.sailing.android.tracking.app/res/values-zh/preferences.xml +++ b/mobile/com.sap.sailing.android.tracking.app/res/values-zh/preferences.xml @@ -1,4 +1,4 @@ - + diff --git a/mobile/com.sap.sailing.android.tracking.app/res/values-zh/strings.xml b/mobile/com.sap.sailing.android.tracking.app/res/values-zh/strings.xml index 4ab1ab4092b..2ada86cc4f8 100644 --- a/mobile/com.sap.sailing.android.tracking.app/res/values-zh/strings.xml +++ b/mobile/com.sap.sailing.android.tracking.app/res/values-zh/strings.xml @@ -1,4 +1,4 @@ - + diff --git a/mobile/com.sap.sailing.android.tracking.app/res/values-zh/strings_dialog.xml b/mobile/com.sap.sailing.android.tracking.app/res/values-zh/strings_dialog.xml index b5521df8eb8..6b1975874fa 100644 --- a/mobile/com.sap.sailing.android.tracking.app/res/values-zh/strings_dialog.xml +++ b/mobile/com.sap.sailing.android.tracking.app/res/values-zh/strings_dialog.xml @@ -1,4 +1,4 @@ - + "是" "否" diff --git a/mobile/com.sap.sailing.android.tracking.app/res/values-zh/strings_fragment.xml b/mobile/com.sap.sailing.android.tracking.app/res/values-zh/strings_fragment.xml index 57e755e944e..218ad7c9606 100644 --- a/mobile/com.sap.sailing.android.tracking.app/res/values-zh/strings_fragment.xml +++ b/mobile/com.sap.sailing.android.tracking.app/res/values-zh/strings_fragment.xml @@ -1,4 +1,4 @@ - + "扫描二维码" "二维码可在确认参与时找到" "没有二维码?" diff --git a/mobile/com.sap.sailing.android.tracking.app/res/values-zh/strings_uss_sailing.xml b/mobile/com.sap.sailing.android.tracking.app/res/values-zh/strings_uss_sailing.xml index 24056f558d5..da3a7450001 100644 --- a/mobile/com.sap.sailing.android.tracking.app/res/values-zh/strings_uss_sailing.xml +++ b/mobile/com.sap.sailing.android.tracking.app/res/values-zh/strings_uss_sailing.xml @@ -1,4 +1,4 @@ - + "SAP Sail InSight 应用通过利用移动电话技术支持赛艇的实时跟踪,朋友和粉丝可以通过实况积分榜和二维可视化在现场或在线跟踪比赛。关注比赛水手可以重播其比赛轮次,以便评估表现并优化 https://www.sapsailing.com 中提供的所有策略\n\nSAP 通过实施一系列创新的技术解决方案为 US Sailing 提供支持,提供分析以帮助船队和水手提高成绩,同时还提供应用程序以使帆船运营更有效率。\n\n作为帆船的全国管理机构,US Sailing 领导这项运动并为其提供全面的发展空间,包括为教练和赛事官员提供培训和教育计划,以及管理和监督全国各地的竞技帆船活动。" diff --git a/mobile/com.sap.sailing.racecommittee.app/res/values-zh/strings.xml b/mobile/com.sap.sailing.racecommittee.app/res/values-zh/strings.xml index 4008e9e619b..74014805c9b 100644 --- a/mobile/com.sap.sailing.racecommittee.app/res/values-zh/strings.xml +++ b/mobile/com.sap.sailing.racecommittee.app/res/values-zh/strings.xml @@ -1,4 +1,4 @@ - + diff --git a/wiki/projects/consolidating-user-stores.md b/wiki/projects/consolidating-user-stores.md new file mode 100644 index 00000000000..327b01dad27 --- /dev/null +++ b/wiki/projects/consolidating-user-stores.md @@ -0,0 +1,285 @@ +# Consolidating User Stores + +[[_TOC_]] + +This document is an evolving set of ideas, requirements and strategies that will lead us to consolidating and joining our SecurityService instances with their embedded UserStore objects into a central shared one for most, and separate ones for a few server instances. The tasks and their history are described in ([bug 4006](https://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=4006) and [bug 4018](https://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=4018)). + +## First Steps +An exported version of the ``USERS``, ``USER_GROUPS`` and ``PREFERENCES`` collections is at ``dbserver.internal.sapsailing.com:/var/lib/mongodb/dump``. The command to obtain this was: +``` + for port in 10201 10202 10203; do echo "rs.slaveOk() + show dbs + quit()" | mongo --port $port | tail -n +5| awk '{print $1;}' | grep -v ^config$ | grep -v ^local$ | grep -v ^admin$ | while read i; do echo $i; for c in USERS PREFERENCES USER_GROUPS; do mongoexport --port $port --db $i -c $c -o dump/${i}_${c}.json; done; done; done +``` +This provides a basis for some initial cross-DB querying, figuring out which conflicts or clashes to expect and developing approaches for consolidation and conflict resolution. + +## Active DBs vs. Inactive DBs vs. "Isolated" DBs + +We have a lot of databases from past events and a few from servers that are actively running. Content from old, inactive servers is obviously less important to recover than content from servers still running. Especially, when conflicts between a record in an inactive and an active DB arises, the active DB should take precedence. + +Records from inactive DBs may not have undergone migration to the ``permission-vertical`` code base, so particularly their roles and permissions as well as user group assignments may be obsolete. There are probably low expectations by those users that their records would ever re-appear or be recovered. Therefore, we may simply decide to ignore old, inactive DBs altogether. + +Other DBs may belong to "isolated" servers from which we don't want content to spill over into a shared SecurityService's user store, such as the ``dev.sapsailing.com`` instance. For other more test-like servers such as ``d-labs.sapsailing.com`` or ``sailtracks.sapsailing.com`` we have to decide whether we'd like those to become part of the shared SecurityService landscape. + +To figure out which databases are active and then classify them into those to be merged and those to remain isolated, we'll start looking at the current server landscape. Eight league servers of which two look at the same DB are still active at this point in time (2019-11-14T16:09:00Z) but will be archived until latest 2019-11-15T18:00:00Z. We therefore implicitly assume their DBs as "inactive." + +There are a few dedicated server instances with their DBs: +* ARCHIVE, DB ``dbserver.internal.sapsailing.com:10201/winddb`` +* AST (Australian Sailing Team), DB ``ast.sapsailing.com:27017/AST`` backed up to ``dbserver.internal.sapsailing.com:10202/AST`` +* The DBs of all instances running on "SL Multi-Instance Kiel" (we should check if we could take this opportunity to shut down those that are still entirely empty): bartlomiejkapusta benjaminalhadef ditlevleth emilienpochet filip frederiksivertsen guentherpachschwoell gustavhultgren hinnerksiemsen janekbalster jassiskogman joanameyerduro jyrikuivalainen konradlipski lukasgrallert mandy marcusbaur martinmaursundrishovd oriolmahiques paulbakker peterwagner rolandregnemer tamarafischer thorbennowak thorechristiansen +* The DBs of all instances running on "SL Multi-Instance Sailing Server NVMe" (we should check if we could take this opportunity to shut down those that are still entirely empty): 49er AARHUSSEJLKLUB abeam-training alarie505 ASVIA baldeneysee BYC d-labs DUTCH_FEDERATION ess-team-training formula18 galvestaure HNV hsc-womensteam irishdbscdw3 ISR JOJOPOLGAR jonaswitt KBSC KJSCS KSSS kyc LYC mdf my NOR oakcliff phoenix PMYC RDSAILING rheinwoche2019 SAILCANADA SAILINGACADEMY sailracer Sailtracks schadewaldt schanzenberg schwielochsee seascape SEGELZENTRUM SINGAPORESAILING SITGES SRN SRV SSC SSV STARLAB TracTracTest ubilabs-test USSAILING VSAW YCL + +bartlomiejkapusta is empty. Removing. benjaminalhadef is largely empty. Removing. mandy is basically empty. Removing. filip is empty. Removing. thorbennowak empty. Removing. lukasgrallert basically empty. Removing. konradlipski only imported old stuff. Removing. gustavhultgren was not even started and had only one old test event. Removing. oriolmahiques has only empty events. Removing. thorechristiansen empty other than Bundesliga imports. Removing. tamarafischer basically empty. Removing. emilienpochet contains only empty events. Removing. paulbakker empty, removing. guentherpachschwoell only has league imports. Removing. rolandregnemer empty; removing. ditlevleth empty; removing. frederiksivertsen empty; removing. jassiskogman empty; removing. jyrikuivalainen empty; removing. martinmaursundrishovd empty; removing. The janekbalster and peterwagner DBs have remained, and their server instances have now been moved to the common multi-instance server. The "SL Multi-Instance Kiel" server has been terminated by now. + +On the "SL Multi-Instance Sailing Server NVMe" server some cleanup is possible, too. I'll remove the ``ubilabs-test`` instance and DB. In particular, "49er" is empty and dead. I'll remove that now. + +So the list of remaining active, non-isolated servers is: +* AARHUSSEJLKLUB +* abeam-training +* alarie505 +* ASVIA +* baldeneysee +* BYC +* DUTCH_FEDERATION +* ess-team-training +* formula18 +* galvestaure +* HNV +* hsc-womensteam +* irishdbscdw3 +* ISR +* janekbalster +* JOJOPOLGAR +* jonaswitt +* KBSC +* KJSCS +* KSSS +* kyc +* LYC +* mdf +* my +* NOR +* oakcliff +* peterwagner +* phoenix +* PMYC +* RDSAILING +* rheinwoche2019 +* SAILCANADA +* SAILINGACADEMY +* sailracer +* schadewaldt +* schanzenberg +* schwielochsee +* seascape +* SEGELZENTRUM +* SINGAPORESAILING +* SITGES +* SRN +* SRV +* SSC +* SSV +* STARLAB +* TracTracTest +* USSAILING +* VSAW +* YCL + +Isolated but active databases that will explicitly not be merged are: +* Sailtracks +* d-labs +* dev + +## Data to Consider + +### ``USERS`` Collection + +Users are identified by their name which in the ``USERS`` collection is represented by the ``NAME`` field. Further attributes are the ``EMAIL``, ``FULLNAME``, ``COMPANY``, ``LOCALE``, ``EMAIL_VALIDATED``, ``PASSWORD_RESET_SECRET`` (in case a reset transaction is currently ongoing), ``VALICATION_SECRET``, then under ``ACCOUNTS`` the username/salted-password content. + +Regarding security, the ``USERS`` collection for each user holds the ``ROLE_IDS`` and the ``PERMISSIONS`` arrays, furthermore the ``DEFAULT_TENANT_IDS`` map whose keys are the ``DEFAULT_TENANT_SERVER`` name and the value providing the ID of the default object creation group for the user on the server identified by the key. + +The roles referenced by the ``ROLE_IDS`` array have a full configuration in the ``ROLES`` table. There are a number of default roles, such as ``user``, ``sailing_viewer`` and ``admin`` for which we want to assume that they have not been altered from their defaults. + +Most DBs have an entry for the <all> user whose key function consists in granting permission to create a new user to everybody, including not logged-on users. + +#### Existing Data + +Special role assignments are those that do not only assign the ``user`` role that any user has: + +``` +for i in *_USERS.json; do output=$( cat $i | jq -r 'select(.ROLE_IDS != null) | select([.ROLE_IDS[] | select(.NAME != "user")] != []) | ("- ".NAME, (.ROLE_IDS[] | select(.NAME != "user") | .NAME":.QUALIFYING_TENANT_NAME ); if [ \! -z "$output" ]; then echo "${i}:"; echo "$output"; fi; done +``` +shows several ``admin`` role assignments and a handful of ``moderator`` assignments. The ``moderator`` assignments are all on servers no longer active or just now under master data import (bundesliga2019.sapsailing.com). Suggestion: ignore the ``moderator`` assignments in case they cause trouble. + +A number of accounts have an unqualified ``admin::`` role assignment. These belong to admins of event servers that have either already been archived or are in the process of being archived. The fact that quite numerous users have been equipped with this global privilege shows two things: +* users seem to be missing something when their ``admin`` role is qualified with the server group (what is this?) +* in the future we must avoid granting this super-power to any but the most trusted "root" users + +The ``PERMISSIONS`` field has entries for a significant number of users, mostly ``SERVER:DATA_MINING`` and ``LEADERBOARD:UPDATE`` entries where the latter seem to have been established mostly for user accounts used on Race Manager App devices. Some inactive instances have permissions set for ``MEDIA_TRACK:CREATE``. On the archive server, two users have explicit ``SERVER:CAN_EXPORT_MASTERDATA:ARCHIVE`` permission. + +The query + +``` +for i in *_USERS.json; do output=$( cat $i | jq -r 'select(.NAME != "" and .PERMISSIONS != [] and .PERMISSIONS != null) | ( .NAME+":", " "+(.PERMISSIONS[] | select(match("DATA_MINING"))) )'); if [ \! -z "$output" ]; then echo " ====== $i ====="; echo "$output"; fi; done| +``` +reveals that there are a number of unqualified ``DATA_MINING`` permissions, one on bundesliga1-2019 which is just about to be archived, one on a recently archived server hwcs2020. And then there is a user "Chelsie2112" with unqualified ``SERVER:DATA_MINING`` access on the archive server. This is being changed now to a qualified ``SERVER:DATA_MINING:ARCHIVE``. + +1856 user records exist in more than one database. + +### ``USER_GROUPS`` Collection + +For all servers there is a ``-server`` group, furthermore for each user that user's personal group, named according the user's name, with ``-tenant`` appended. The ``USERNAMES`` array contains the user name keys identifying the users that are part of this group. + +The ``ROLE_DEFINITION_MAP`` array has entries referencing a role definition by UUID in the field ``ROLE_DEFINITION_MAP_ROLE_ID`` and defining whether or not the permissions implied by that role shall be granted for access to objects owned by the group only to users belonging to the group or to all users (field ``ROLE_DEFINITION_MAP_FOR_ALL``). + +#### Existing Data + +For all user groups (active and inactive server DBs) there is only one group that has a role assigned that is not the ``sailing_viewer`` role: + +``` +for i in *_USER_GROUPS.json; do output=$( cat $i | jq -r 'select(.NAME | (test("-tenant$") or test("-server$")) | not) | select((.ROLE_DEFINITION_MAP[] | select((.ROLE_DEFINITION_MAP_ROLE_ID | .["$binary"]) != "y0V7Ud9IKcQV4Rif59Gpnw==") | length) >= 1) | (" "+.NAME, (.ROLE_DEFINITION_MAP[] | select((.ROLE_DEFINITION_MAP_ROLE_ID | .["$binary"]) != "y0V7Ud9IKcQV4Rif59Gpnw==")) )' ); if [ \! -z "$output" ]; then echo " ===== ${i} ====="; echo "$output"; fi; done +``` +yields + +``` + ===== d-labs_USER_GROUPS.json ===== + StefansTestEventGroup +{ + "ROLE_DEFINITION_MAP_ROLE_ID": { + "$binary": "ZEQ9sUhRHa0uTk1uOXzEkA==", + "$type": "03" + }, + "ROLE_DEFINITION_MAP_FOR_ALL": false +} +``` +In all other cases, groups either have no role assignment or assign the ``sailing_viewer`` role. Of those, only two assign the role only to the users of their group: + +``` +for i in *_USER_GROUPS.json; do output=$( cat $i | jq -r 'select(.NAME | (test("-tenant$") or test("-server$")) | no) | select(.ROLE_DEFINITION_MAP[] | select((.ROLE_DEFINITION_MAP_ROLE_ID | .["$binary"]) == "y0V7Ud9IKcQV4Rif59Gpnw==" and .ROLE_DEFINITION_MAP_FOR_ALL==false)) | (" "+.NAME, .ROLE_DEFINITION_MAP[] )' ); if [ \! -z "$output" ]; then echo " ===== ${i} ====="; echo "$output"; fi; done +``` +yields + +``` + ===== dev_USER_GROUPS.json ===== + Secret-test-group +{ + "ROLE_DEFINITION_MAP_ROLE_ID": { + "$binary": "y0V7Ud9IKcQV4Rif59Gpnw==", + "$type": "03" + }, + "ROLE_DEFINITION_MAP_FOR_ALL": false +} + ===== d-labs_USER_GROUPS.json ===== + AxelsSecretTestGroup +{ + "ROLE_DEFINITION_MAP_ROLE_ID": { + "$binary": "y0V7Ud9IKcQV4Rif59Gpnw==", + "$type": "03" + }, + "ROLE_DEFINITION_MAP_FOR_ALL": false +} +``` +and both are test groups in the isolated servers "dev" and "d-labs" so would not need further consideration in case of problems with this constellation. + +### ``PREFERENCES`` Collection + +This collection can contain string-based key/value pairs for users identified by their user name which is given in the ``USERNAME`` attribute. The ``KEYS_AND_VALUES`` array has objects with a ``KEY`` and a ``VALUE`` attribute each. One typical key is the ``___access_token___`` key where the value contains the API access token that, when sent with a REST request's ``Authorization`` header field, is good for authenticating the corresponding user. + +Other than the access token, the ``KEYS_AND_VALUES`` array is used largely to store user settings from the various components, with or without a "document" qualification, such as with keys ``sailing.ui.usersettings.SeriesOverallLeaderboard#Allsvenskan Segling 2019 Overall`` or ``sailing.ui.usersettings.Raceboard.WINNING_LANES#WCS 2019 Marseille - RS:X Men,R9 (RS:X Men),WCS 2019 Marseille - RS:X Men``. + +#### Existing Data + +There are currently 2998 distinct keys used. An interesting one could have been ``sailing.datamining.storedqueries`` but it turns out that up to now there are only eight occurrences of this key across the landscape, so the feature of storing data mining queries does not seem to be in "overly active use" and no dedicated merging / migration strategy seems required. + +Overall we have 24623 keys in all ``PREFERENCES`` collections out of which 872 use the ``___access_token___`` key. + +### Scripts for Data Extraction + +Obtaining users with non-default ("user") role assignments: + +``` +for i in *_USERS.json; do output=$( cat $i | jq -r 'select(.ROLE_IDS != null) | select([.ROLE_IDS[] | select(.NAME != "user")] != []) | ("- "+.NAME, (.ROLE_IDS[] | select(.NAME != "user") | .NAME+":"+.QUALIFYING_TENANT_NAME+":"+.QUALIFYING_USERNAME ))'); if [ \! -z "$output" ]; then echo " ===== ${i} ====="; echo "$output"; fi; done +``` + +Obtaining the users that are not the <all> user and have non-empty permissions: + +``` +for i in *_USERS.json; do output=$( cat $i | jq -r 'select(.NAME != "" and .PERMISSIONS != [] and .PERMISSIONS != null) | ( .NAME+":", " "+.PERMISSIONS[] )'); if [ \! -z "$output" ]; then echo " ====== $i ====="; echo "$output"; fi; done +``` + +Finding user groups that are not the regular ``-tenant`` or ``-server`` groups: + +``` +for i in *_USER_GROUPS.json; do output=$( cat $i | jq -r 'select(.NAME | (test("-tenant$") or test("-server$")) | not).NAME' ); if [ \! -z "$output" ]; then echo " ${i} "; echo "$output"; fi; done +``` + +Finding user groups with more than one user in it: + +``` +for i in *_USER_GROUPS.json; do output=$( cat $i | jq -r 'select(.NAME | (test("-tenant$") or test("-server$")) | not) | select((.USERNAMES | length) > 1) | (" "+.NAME, .USERNAMES[])' ); if [ \! -z "$output" ]; then echo " ===== ${i} ====="; echo "$output"; fi; done +``` + +Finding non-distinct users after having stored all sorted user names including duplicates in ``/tmp/all_users_name.json`` and all uniquely sorted user names in ``/tmp/unique_users_name.json``: + +``` +diff /tmp/all_users_name.json /tmp/unique_users_name.json | grep "^[<>]" | sed -e 's/^[<>] "//' -e 's/"$//' | sort -u | wc + 1856 1936 16642 +``` + +Under the same premise regarding the input files, + +``` +diff /tmp/all_users_name.json /tmp/unique_users_name.json | grep "^[<>]" | sed -e 's/^[<>] "//' -e 's/"$//' | sort -u | while read i; do echo $i; cat *_USERS.json | jq .NAME | grep -c $i; done +``` +lists all users with the number of their occurrences + +List all databases used by a multi-instance server: + +``` +for i in */env.sh; do cat $i | grep "\(MONGODB_URI\)\|\(MONGODB_NAME\)" | grep -v "^#" | sed -e 's/MONGODB_NAME=\(.*\)$/\1/' -e 's/MONGODB_URI=.*\/\([^?]*\)\?.*$/\1/' | tail -n 1; done | while read n; do echo -n "$n "; done +``` + +## Strategy and Approach for Merging the Collections + +As the starting point we should use the ``winddb`` ARCHIVE server's MongoDB collections ``USERS``, ``PREFERENCES``, and ``USER_GROUPS``. We will ignore all databases from inactive servers, including all content archived during the end of the 2019 season. Further collections to consider are the ``ACCESS_CONTROL_LIST`` and ``OWNERSHIPS`` collections. + +Remaining to be added to the ``winddb`` content are the same collections from all active, non-isolated servers (see above). + +### Algorithm for Merging + +Start with the ``USERS`` collection of the database to be merged. For each username check if that name already exists in the target collection into which to merge. If no, copy the record. If yes, log this and compare the e-mail addresses. If they do not match, log this because it is not clear the records belong to the same subject, and no merge attempt will be made. Otherwise, the merge process will consider the ``ROLE_IDS`` and ``PERMISSIONS`` fields, as well as the ``DEFAULT_TENANT_IDS`` field and will set the ``EMAIL_VALIDATED`` field to ``true`` if either one of the two was ``true``. For the role assignments we will make sure that no unqualified assignments are merged. Furthermore, a role referenced in the ``ROLE_IDS`` will only be merged if the role's ID exists in the target's ``ROLE_DEFINITIONS`` collection. According to the research above, only ``user``, ``admin`` and ``moderator`` assignments seem to exist and those are pre-defined roles that will exist in the target with the same IDs. During a merge we won't touch the account and password information. Users affected by a merge will therefore end up with the username/password combination they have on the ARCHIVE server. Should that be different and should they have forgotten, they can still recover the password. + +Before merging a permission into the ``PERMISSIONS`` array of the ``USERS`` collection we have to ensure proper qualification. The ``SERVER:DATAMINING`` permission must be constrained to the server name from where the record is being merged. This can easiest be established by stepping through the permissions granted on the active servers to be merged. Only 49er, HNV, my, NOR, sailracer, SRV and VSAW have such records, and I'll qualify or remove any unqualified permissions. (Side note: currently, due to bug 5156 it is not possible to remove those erroneous permission assignments. However, a fix is underway with commit 841893528be759d11f776bb1c437e61ffc66dccf and as soon as a release becomes available we can upgrade the servers that require it.) + +Remaining permissions to clean up: + +``` + ====== HNV ===== +Johannes.Hellmich: + admin + ====== NOR ===== +saillogic: + manage_device_configuration:* + leaderboard:update:* + ====== sailracer ===== +Kai: + admin + ====== SRV ===== +Max: + Admin + ====== VSAW ===== +peter: + MANAGE_DEVICE_CONFIGURATION +``` + +Cleaned up permissions as of 2019-11-15T23:50:00Z. + +The ``PREFERENCES`` collection can be merged based on user name, such that in case of conflicting preference key the collection to merge into will "win." + +Merging the ``USER_GROUPS`` collection should be straightforward. They will be copied if they don't exist on the importing side. Should a user group with the same ID exist, their set of users will be merged and their set of roles will be merged. + +``OWNERSHIPS`` and ``ACCESS_CONTROL_LISTS`` need to be checked for conflicts in object IDs first... TODO + +## Open Issues + +Should we implement a migration of Local Storage properties? If a server is configured to use a cross-domain storage and under the application origin's local storage there exist one or more properties, should we make an effort to copy those into the shared cross-domain storage? How to resolve conflicts there? \ No newline at end of file