Merge branch 'master' into translation

This commit is contained in:
Axel Uhl
2022-05-12 17:46:15 +02:00
84 changed files with 1111 additions and 360 deletions
@@ -22,6 +22,7 @@ import com.sap.sse.security.ui.client.UserService;
import com.sap.sse.security.ui.client.UserStatusEventHandler;
import com.sap.sse.security.ui.client.WithSecurity;
import com.sap.sse.security.ui.client.i18n.StringMessages;
import com.sap.sse.security.ui.client.premium.PaywallResolver;
import com.sap.sse.security.ui.shared.SuccessInfo;
/**
@@ -39,6 +40,7 @@ public class AuthenticationManagerImpl implements AuthenticationManager {
private final EventBus eventBus;
private final String emailConfirmationUrl;
private final String passwordResetUrl;
private final PaywallResolver paywallResolver;
private final StringMessages i18n = StringMessages.INSTANCE;
private final ErrorMessageView view = new ErrorMessageViewImpl();
@@ -57,8 +59,9 @@ public class AuthenticationManagerImpl implements AuthenticationManager {
*/
public AuthenticationManagerImpl(WithSecurity clientFactory, EventBus eventBus,
String emailConfirmationUrl, String passwordResetUrl) {
this(clientFactory.getUserManagementWriteService(), clientFactory.getUserService(), eventBus, emailConfirmationUrl,
passwordResetUrl);
this(clientFactory.getUserManagementWriteService(), clientFactory.getUserService(),
new PaywallResolver(clientFactory.getUserService(), clientFactory.getSubscriptionServiceFactory()),
eventBus, emailConfirmationUrl, passwordResetUrl);
}
/**
@@ -74,22 +77,23 @@ public class AuthenticationManagerImpl implements AuthenticationManager {
* @param passwordResetUrl
* URL which is send to users to reset their password
*/
public AuthenticationManagerImpl(UserService userService, EventBus eventBus, String emailConfirmationUrl,
String passwordResetUrl) {
this(userService.getUserManagementWriteService(), userService, eventBus, emailConfirmationUrl, passwordResetUrl);
public AuthenticationManagerImpl(UserService userService, PaywallResolver paywallResolver,
EventBus eventBus, String emailConfirmationUrl, String passwordResetUrl) {
this(userService.getUserManagementWriteService(), userService, paywallResolver, eventBus, emailConfirmationUrl, passwordResetUrl);
}
private AuthenticationManagerImpl(UserManagementWriteServiceAsync userManagementWriteService, UserService userService,
final EventBus eventBus, String emailConfirmationUrl, String passwordResetUrl) {
PaywallResolver paywallResolver, final EventBus eventBus, String emailConfirmationUrl, String passwordResetUrl) {
this.userManagementWriteService = userManagementWriteService;
this.userService = userService;
this.eventBus = eventBus;
this.emailConfirmationUrl = emailConfirmationUrl;
this.passwordResetUrl = passwordResetUrl;
this.paywallResolver = paywallResolver;
userService.addUserStatusEventHandler(new UserStatusEventHandler() {
@Override
public void onUserStatusChange(UserDTO user, boolean preAuthenticated) {
eventBus.fireEvent(new AuthenticationContextEvent(new AuthenticationContextImpl(user, userService)));
eventBus.fireEvent(new AuthenticationContextEvent(new AuthenticationContextImpl(user, userService, paywallResolver)));
}
});
eventBus.addHandler(AuthenticationSignOutRequestEvent.TYPE, new AuthenticationSignOutRequestEvent.Handler() {
@@ -250,7 +254,7 @@ public class AuthenticationManagerImpl implements AuthenticationManager {
@Override
public AuthenticationContext getAuthenticationContext() {
return new AuthenticationContextImpl(userService.getCurrentUser(), userService);
return new AuthenticationContextImpl(userService.getCurrentUser(), userService, paywallResolver);
}
@Override
@@ -4,6 +4,7 @@ import com.sap.sse.gwt.client.ServerInfoDTO;
import com.sap.sse.security.shared.HasPermissions.Action;
import com.sap.sse.security.shared.dto.SecuredDTO;
import com.sap.sse.security.shared.dto.UserDTO;
import com.sap.sse.security.ui.client.premium.PaywallResolver;
/**
* Interface for authentication context representations providing access to the current {@link UserDTO user} object and
@@ -46,4 +47,6 @@ public interface AuthenticationContext {
boolean hasServerPermission(Action action);
ServerInfoDTO getServerInfo();
PaywallResolver getPaywallResolver();
}
@@ -10,6 +10,7 @@ import com.sap.sse.security.shared.dto.SecuredDTO;
import com.sap.sse.security.shared.dto.UserDTO;
import com.sap.sse.security.shared.dto.WildcardPermissionWithSecurityDTO;
import com.sap.sse.security.ui.client.UserService;
import com.sap.sse.security.ui.client.premium.PaywallResolver;
/**
* Default implementation of {@link AuthenticationContext}.
@@ -22,6 +23,7 @@ public class AuthenticationContextImpl implements AuthenticationContext {
new ArrayList<WildcardPermissionWithSecurityDTO>(),
/* groups */ null);
private final UserService userService;
private final PaywallResolver paywallResolver;
/**
* Creating an {@link AuthenticationContextImpl} containing the given {@link UserDTO} object.
@@ -29,8 +31,9 @@ public class AuthenticationContextImpl implements AuthenticationContext {
* @param currentUser
* the current {@link UserDTO user} object
*/
public AuthenticationContextImpl(UserDTO currentUser, UserService userService) {
public AuthenticationContextImpl(UserDTO currentUser, UserService userService, PaywallResolver paywallResolver) {
this.userService = userService;
this.paywallResolver = paywallResolver;
if (currentUser == null) {
this.currentUser = ANONYMOUS;
} else {
@@ -84,4 +87,9 @@ public class AuthenticationContextImpl implements AuthenticationContext {
public ServerInfoDTO getServerInfo() {
return userService.getServerInfo();
}
@Override
public PaywallResolver getPaywallResolver() {
return paywallResolver;
}
}
@@ -13,6 +13,7 @@ import com.sap.sse.security.ui.authentication.view.AuthenticationMenuView;
import com.sap.sse.security.ui.authentication.view.FlyoutAuthenticationPresenter;
import com.sap.sse.security.ui.authentication.view.FlyoutAuthenticationView;
import com.sap.sse.security.ui.client.UserService;
import com.sap.sse.security.ui.client.premium.PaywallResolver;
/**
* Configures the authentication framework in a common way that is suitable for generic flyout based authentication.
@@ -25,9 +26,9 @@ public class GenericAuthentication {
private final EventBus eventBus = new SimpleEventBus();
private final AuthenticationManager manager;
public GenericAuthentication(UserService userService, AuthenticationMenuView menuView,
public GenericAuthentication(UserService userService, PaywallResolver paywallResolver, AuthenticationMenuView menuView,
FlyoutAuthenticationView display, GenericAuthenticationLinkFactory linkFactory, CommonSharedResources res) {
manager = new AuthenticationManagerImpl(userService, eventBus,
manager = new AuthenticationManagerImpl(userService, paywallResolver, eventBus,
linkFactory.createEmailValidationLink(), linkFactory.createPasswordResetLink());
final AuthenticationClientFactory clientFactory = new AuthenticationClientFactoryImpl(manager, res);
final GenericAuthenticationCallbackImpl callback = new GenericAuthenticationCallbackImpl(linkFactory);
@@ -37,7 +37,8 @@ public class SAPHeaderWithAuthentication extends SAPHeader {
Anchor authenticationMenu = new Anchor();
authenticationMenu.addStyleName(res.css().usermanagement_icon());
rightWithAuthentication.add(authenticationMenu);
authenticationMenuView = new AuthenticationMenuViewImpl(authenticationMenu, res.css().usermanagement_loggedin(), res.css().usermanagement_open());
authenticationMenuView = new AuthenticationMenuViewImpl(authenticationMenu, res.css().usermanagement_loggedin(),
res.css().usermanagement_open(), res.css().user_menu_premium());
rightWrapper = new SimplePanel();
rightWrapper.addStyleName(res.css().header_right_extension());
rightWithAuthentication.add(rightWrapper);
@@ -48,9 +49,10 @@ public class SAPHeaderWithAuthentication extends SAPHeader {
public void addWidgetToRightSide(Widget widget) {
rightWrapper.add(widget);
}
/**
* @return the {@link AuthenticationMenuView} associated with the authentication control on the right side of the header.
* @return the {@link AuthenticationMenuView} associated with the authentication control on the right side of the
* header.
*/
public AuthenticationMenuView getAuthenticationMenuView() {
return authenticationMenuView;
@@ -4,23 +4,22 @@ import com.google.gwt.core.client.GWT;
import com.google.gwt.resources.client.CssResource;
import com.sap.sse.security.ui.authentication.generic.resource.AuthenticationResources;
public interface SAPHeaderWithAuthenticationResources extends AuthenticationResources {
public static final SAPHeaderWithAuthenticationResources INSTANCE = GWT.create(SAPHeaderWithAuthenticationResources.class);
public static final SAPHeaderWithAuthenticationResources INSTANCE = GWT
.create(SAPHeaderWithAuthenticationResources.class);
@Source("header-with-authentication.gss")
HeaderWithAuthenticationCss css();
public interface HeaderWithAuthenticationCss extends CssResource {
String header_right_wrapper();
String header_right_extension();
String fixed();
String usermanagement_icon();
String usermanagement_loggedin();
String usermanagement_view();
String usermanagement_open();
String user_menu_premium();
String languageSelector();
}
}
@@ -53,3 +53,17 @@
font-size: 100% !important;
font-weight: normal;
}
.user_menu_premium {
position: absolute;
bottom: -2px;
left: 50%;
transform: translate(-50%, 0%);
margin: 0;
padding: 0 3px;
font-size: 9px;
font-weight: bold;
color: #fff;
background: #efaa00;
line-height: 12px;
border-radius: 0.33em;
}
@@ -6,7 +6,7 @@ import com.google.gwt.user.client.ui.IsWidget;
* Interface for menu items, which interacting with a {@link FlyoutAuthenticationView}.
*/
public interface AuthenticationMenuView extends IsWidget {
/**
* Sets the {@link Presenter}.
*
@@ -14,7 +14,7 @@ public interface AuthenticationMenuView extends IsWidget {
* the {@link Presenter} to set
*/
void setPresenter(Presenter presenter);
/**
* Sets whether or not there is an authenticated user.
*
@@ -22,7 +22,7 @@ public interface AuthenticationMenuView extends IsWidget {
* <code>true</code> if there is an authenticated user, <code>false</code> otherwise
*/
void setAuthenticated(boolean authenticated);
/**
* Sets whether or not the {@link FlyoutAuthenticationView} is open/shown.
*
@@ -30,7 +30,15 @@ public interface AuthenticationMenuView extends IsWidget {
* <code>true</code> the {@link FlyoutAuthenticationView} is open, <code>false</code> otherwise
*/
void setOpen(boolean open);
/**
* Shows the premium indicator below the user icon.
*
* @param premium
* if premium is visible (active premium role) or not.
*/
void showPremium(boolean premium);
/**
* Presenter interface to toggle {@link FlyoutAuthenticationView}'s visibility.
*/
@@ -4,17 +4,20 @@ import com.google.gwt.debug.client.DebugInfo;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sse.security.ui.client.i18n.StringMessages;
/**
* Default implementation of {@link AuthenticationMenuView} based on an {@link Anchor} widget.
*/
public class AuthenticationMenuViewImpl implements AuthenticationMenuView {
private Presenter presenter;
private final Anchor anchor;
private final String loggedInStyle;
private final String openStyle;
private final Label usermenuPremium;
/**
* Create a new {@link AuthenticationMenuViewImpl} instance with the given parameters.
@@ -26,7 +29,7 @@ public class AuthenticationMenuViewImpl implements AuthenticationMenuView {
* @param openStyle
* the style name to add to the widget, if the {@link FlyoutAuthenticationView} is open
*/
public AuthenticationMenuViewImpl(Anchor anchor, String loggedInStyle, String openStyle) {
public AuthenticationMenuViewImpl(Anchor anchor, String loggedInStyle, String openStyle, String premiumStyle) {
this.anchor = anchor;
this.loggedInStyle = loggedInStyle;
this.openStyle = openStyle;
@@ -37,6 +40,10 @@ public class AuthenticationMenuViewImpl implements AuthenticationMenuView {
}
});
this.anchor.ensureDebugId("authenticationMenu");
usermenuPremium = new Label(StringMessages.INSTANCE.premium());
usermenuPremium.addStyleName(premiumStyle);
usermenuPremium.setVisible(false);
this.anchor.getElement().appendChild(usermenuPremium.getElement());
}
@Override
@@ -54,13 +61,18 @@ public class AuthenticationMenuViewImpl implements AuthenticationMenuView {
anchor.setStyleName(loggedInStyle, authenticated);
setDebugDataAttribute("data-auth", authenticated);
}
@Override
public void setOpen(boolean open) {
anchor.setStyleName(openStyle, open);
setDebugDataAttribute("data-open", open);
}
@Override
public void showPremium(boolean premium) {
usermenuPremium.setVisible(premium);
}
private void setDebugDataAttribute(String name, boolean value) {
if (DebugInfo.isDebugIdEnabled()) {
anchor.getElement().setAttribute(name, String.valueOf(value));
@@ -1,6 +1,7 @@
package com.sap.sse.security.ui.authentication.view;
import com.google.web.bindery.event.shared.EventBus;
import com.sap.sse.security.shared.impl.SecuredSecurityTypes.UserActions;
import com.sap.sse.security.ui.authentication.AuthenticationContextEvent;
import com.sap.sse.security.ui.authentication.AuthenticationPlaceManagementController;
import com.sap.sse.security.ui.authentication.AuthenticationRequestEvent;
@@ -55,9 +56,11 @@ public class FlyoutAuthenticationPresenter implements AuthenticationMenuView.Pre
@Override
public void onUserChangeEvent(AuthenticationContextEvent event) {
authenticationMenuView.setAuthenticated(event.getCtx().isLoggedIn());
authenticationMenuView.showPremium(event.getCtx().hasPermission(event.getCtx().getCurrentUser(), UserActions.BE_PREMIUM));
}
});
authenticationMenuView.setAuthenticated(initialAuthentication.isLoggedIn());
authenticationMenuView.showPremium(initialAuthentication.hasPermission(initialAuthentication.getCurrentUser(), UserActions.BE_PREMIUM));
}
public void showRegister() {
@@ -206,6 +206,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages {
String selectSubscriptionPlan();
String features();
String premiumFeature();
String premium();
String price();
String pleaseSubscribeToUse();
String pleaseSubscribeToUseSpecific(String actionName);
@@ -213,6 +213,7 @@ premiumFeatureListDescription=Compare all the features provided in the FREE or P
selectSubscriptionPlan=Please select a subscription plan to subscribe to.
features=Features
premiumFeature=Premium-Feature
premium=Premium
price=Price
pleaseSubscribeToUse=You do not have permission to use this feature. Consider Subscribing.
pleaseSubscribeToUseSpecific=You do not have permission to use the feature "{0}". Consider acquiring a subscription plan.
@@ -223,4 +224,4 @@ subscriptionSuggestionTitle=Lacking Permission
takeMeToSubscriptions=Go to subscription plans.
errorPollingCheckoutResults=Could not retrieve payment status.
paymentUnfinished=Waiting for payment to process.
paymentFinished=Payment successful. Premium roles have been granted.
paymentFinished=Payment successful. Plan roles have been granted.
@@ -221,4 +221,4 @@ subscriptionSuggestionTitle=Fehlende Befugnis
takeMeToSubscriptions=Zur Abbonementübersicht
errorPollingCheckoutResults=Der Zahlungsstatus konnte nicht abgerufen werden.
paymentUnfinished=Warte auf Zahlungsbestätigung.
paymentFinished=Zahlung erfolgreich. Premium Rolle verliehen.
paymentFinished=Zahlung erfolgreich. Planrollen wurden verliehen.
@@ -20,22 +20,22 @@ public interface SubscriptionStringConstants extends ConstantsWithLookup {
String free_subscription_plan_description();
String free_subscription_plan_info();
String free_subscription_plan_price_info();
String[] free_subscription_plan_features();
String yearly_premium_name();
String yearly_premium_description();
String yearly_premium_price_info();
String yearly_premium_info();
String[] yearly_premium_features();
String weekly_premium_name();
String weekly_premium_description();
String weekly_premium_price_info();
String weekly_premium_info();
String[] weekly_premium_features();
String trial_premium_name();
String trial_premium_description();
String trial_premium_price_info();
String trial_premium_info();
String[] trial_premium_features();
String free_subscription_plan_features();
String premium_name();
String premium_description();
String premium_price_info();
String premium_info();
String premium_features();
String data_mining_archive_name();
String data_mining_archive_description();
String data_mining_archive_price_info();
String data_mining_archive_info();
String data_mining_archive_features();
String data_mining_all_name();
String data_mining_all_description();
String data_mining_all_price_info();
String data_mining_all_info();
String data_mining_all_features();
String free_subscription_plan_shortname();
String premium_subscription_plan_shortname();
String datamining_subscription_plan_shortname();
@@ -71,4 +71,6 @@ public interface SubscriptionStringConstants extends ConstantsWithLookup {
String features_media_tags_description();
String features_scoring_title();
String features_scoring_description();
String features_data_mining_title();
String features_data_mining_description();
}
@@ -18,29 +18,31 @@ free_subscription_plan_name=Free
free_subscription_plan_description=Try it out
free_subscription_plan_info=
free_subscription_plan_price_info=
free_subscription_plan_features=Basic live wind based leaderboard,\
free_subscription_plan_features=Basic live wind based leaderboard|\
Create your own account and carry out the sailing analytics for your regatta or training with our \
free tracking app or a professional tracking service,\
free tracking app or a professional tracking service|\
Sync live YouTube videos with your races
yearly_premium_name=Yearly Premium
yearly_premium_description=Full Access to all Features for one Year (auto renewing)
yearly_premium_info=Everything from Weekly Premium for a year, at a discount!
yearly_premium_price_info=
yearly_premium_features=\
Full live analytics with hundreds of features including wind streamlets, comparison charts, \
advanced in-map visualizations and much more. See full premium feature-list below, \
Tag Personal Timeline with Videos and Notes
weekly_premium_name=Weekly Premium
weekly_premium_description=Full Access to all Features for one Week (one time payment)
weekly_premium_info=Everything from free plan plus:
weekly_premium_price_info=One time payment
weekly_premium_features=\
Full live analytics with hundreds of features including wind streamlets, comparison charts, \
advanced in-map visualizations and much more. See full premium feature-list below, \
premium_name=Premium
premium_description=All the premium features.
premium_info=Everything from free plan plus:
premium_price_info=One Time Payment
premium_features=\
Full Live Analytics with hundreds of features including wind streamlets|comparison charts|\
advanced in-map visualizations and much more. See full premium feature-list below|\
Tag Personal Timeline with Videos and Notes
data_mining_archive_name=Data Mining - Archive
data_mining_archive_description=Data Mining across archived races and events.
data_mining_archive_info=Everything from premium plan plus:
data_mining_archive_price_info=One Time Payment
data_mining_archive_features=Powerful data mining for archived races and events that can be found under www.sapsailing.com
data_mining_all_name=Data Mining - ALL
data_mining_all_description=Data Mining across all races and events
data_mining_all_info=Everything from data mining archive plan plus:
data_mining_all_price_info=One Time Payment
data_mining_all_features=Powerful data mining including additional data from all sub domains of sapsailing.com, e.g.: for leagues, live events or club servers
free_subscription_plan_shortname=free
premium_subscription_plan_shortname=premium
datamining_subscription_plan_shortname=data-mining
datamining_subscription_plan_shortname=data mining
features_limited_live_analytics_title=Live Analytics (limited)
features_limited_live_analytics_description=Limited Live Analytics.
features_full_live_analytics_title=Live Analytics (full)
@@ -48,37 +50,33 @@ features_full_live_analytics_description=Full live analytics with hundreds of fe
features_organize_events_title=Organize Events
features_organize_events_description=Run the Sailing Analytics at your Regatta with our free tracking app or a professional tracking service*. (below: *Like Trac Trac ) Maneuever detection and Analytics
features_events_with_more_regatta_title=Events with more than one regatta
features_events_with_more_regatta_description=-
features_events_with_more_regatta_description=You can create a multi-class event or a season of events counting in a seasonal leaderboard
features_connect_to_tractrac_title=Connect to Trac Trac
features_connect_to_tractrac_description=Connect to professional tracking service
features_imports_title=Import external data
features_imports_description=Import GPX and KML file formats
features_imports_description=Import GPX and KML file formats, GRIB files and Expedition logs
features_media_management_title=Media Management
features_media_management_description=Integrate/upload and replay video and Pictures
features_analytic_charts_title=Analytic Charts
features_analytic_charts_description=Charts like...
features_analytic_charts_description=Charts for comparing competitor performance, wind strip charts and a table for maneuver analysis and comparison
features_media_tags_title=Link and upload media (tags)
features_media_tags_description= Place and read comments (notes and images on timeline)
features_scoring_title=Scoring
features_scoring_description=ORC PCS scoring
trial_premium_name=Trial
trial_premium_description=A short trial experience of the premium features. Lasts a day.
trial_premium_info=Everything from free plan plus:
trial_premium_price_info=
trial_premium_features=\
Full live analytics with hundreds of features including wind streamlets, comparison charts, \
advanced in-map visualizations and much more. See full premium feature-list below, \
Tag Personal Timeline with Videos and Notes
features_scoring_description=Low-Point, High-Point, various tie breaking variants, ToT/ToD as well as ORC Performance Curve Scoring handicap support
features_map_analytics_title=Map Analytics
features_map_analytics_description=Wind streamlets.
features_simulator_title=Simulator
features_simulator_description=Simulation and analysis.
features_advanced_leaderboard_info_title=Detailed leaderboard information
features_advanced_leaderboard_info_description=Advanced leaderboard information. E.g. gap to leader.
features_advanced_leaderboard_info_description=Advanced leaderboard information, e.g. gap to leader, speed over ground, maneuvers, velocity made good (VMG) and cross-track error (XTE)
features_competitor_analytics_title=Competitor analysis
features_competitor_analytics_description=Advanced competitor analytics.
features_competitor_analytics_description=Advanced competitor analytics charts with values such as speed over ground (SOG), true wind angle (TWA), gap to leader and velocity made good (VMG)
features_maneuver_analytics_title=Maneuver Analytics
features_maneuver_analytics_description=Advanced analytics regarding maneuver execution of competitors.
features_maneuver_analytics_description=Advanced analytics regarding maneuver execution of competitors, including maneuver loss, turn rate and maneuver angle
features_wind_analytics_title=Wind analytics
features_wind_analytics_description=Advanced analytics regarding collected wind data.
features_wind_analytics_description=Advanced analytics regarding collected wind data; colored animated overlay and strip charts for every wind source considered
features_data_mining_title=Data Mining
features_data_mining_description=Data Mining across races and events. \
Depending on plan type for archive only (everything that can be found under www.sapsailing.com) \
or all sub domains (e.g. for leagues, live events or club servers)
@@ -20,28 +20,30 @@ free_subscription_plan_name=Free
free_subscription_plan_description=Probier es aus
free_subscription_plan_info=
free_subscription_plan_price_info=
free_subscription_plan_features=Standart Live-Wind-basierte Bestenliste,\
Erstellen Sie Ihr eigenes Konto und führen Sie die Segelanalyse für Ihre Regatta oder Ihr Training mit unserer kostenlosen Tracking-App oder einem professionellen Tracking-Service durch,\
free_subscription_plan_features=Standart Live-Wind-basierte Bestenliste|\
Erstellen Sie Ihr eigenes Konto und führen Sie die Segelanalyse für Ihre Regatta oder Ihr Training mit unserer kostenlosen Tracking-App oder einem professionellen Tracking-Service durch|\
Synchronisiere YouTube-Videos mit deinen Rennen
yearly_premium_name=Jahresabo
yearly_premium_description=Ein Jahr Premium. Wiederkehrend.
yearly_premium_info=Alles aus dem Wochenabo für ein Jahr und mit einem Rabatt!
yearly_premium_price_info=
yearly_premium_features=\
Vollständige Live-Analyse mit Hunderten von Funktionen, einschließlich Windströmungen, Vergleichstabellen, \
erweiterte In-Map-Visualisierungen und vieles mehr. Siehe die vollständige Liste der Premiumfunktionen unten, \
Kennzeichnen Sie die persönliche Timeline mit Videos und Notizen
weekly_premium_name=Wochenabo
weekly_premium_description=Voller Zugriff auf alle Funktionen für eine Woche (einmalige Zahlung)
weekly_premium_info=Alles vom kostenlosen Plan plus:
weekly_premium_price_info=einmalige Zahlung
weekly_premium_features=\
Vollständige Live-Analyse mit Hunderten von Funktionen, einschließlich Windströmungen, Vergleichstabellen, \
erweiterte In-Map-Visualisierungen und vieles mehr. Siehe die vollständige Liste der Premiumfunktionen unten, \
premium_name=Premium
premium_description=Eine kurze Kostprobe der Premiummitgliedschaft. Läuft einen Tag.
premium_info=Alles vom kostenlosen Plan plus:
premium_price_info=einmalige Zahlung
premium_features=\
Vollständige Live-Analyse mit Hunderten von Funktionen|einschließlich Windströmungen|Vergleichstabellen|\
erweiterte In-Map-Visualisierungen und vieles mehr. Siehe die vollständige Liste der Premiumfunktionen unten|\
Kennzeichnen Sie die persönliche Timeline mit Videos und Notizen
data_mining_archive_name=Data Mining - Archive
data_mining_archive_description=Data Mining über archivierte Rennen und Veranstaltungen hinweg.
data_mining_archive_info=
data_mining_archive_price_info=einmalige Zahlung
data_mining_archive_features=Leistungsstarkes Data Mining für archivierte Rennen und Veranstaltungen, die unter www.sapsailing.com zu finden sind
data_mining_all_name=Data Mining - All
data_mining_all_description=Data Mining über alle Rennen und Events hinweg
data_mining_all_info=
data_mining_all_price_info=einmalige Zahlung
data_mining_all_features=Leistungsstarkes Data Mining inklusive zusätzlicher Daten aus allen Subdomains von sapsailing.com, z. B.: für Ligen, Live-Events oder Clubserver
free_subscription_plan_shortname=free
premium_subscription_plan_shortname=premium
datamining_subscription_plan_shortname=data-mining
datamining_subscription_plan_shortname=data mining
features_limited_live_analytics_title=Live Analytics (limitiert)
features_limited_live_analytics_description=Limitierte Live-Analyse.
features_full_live_analytics_title=Live Analytics (vollständig)
@@ -49,36 +51,32 @@ features_full_live_analytics_description=Vollständige Live-Analyse mit Hunderte
features_organize_events_title=Veranstaltungen organisieren
features_organize_events_description=Führen Sie die Sailing Analytics bei Ihrer Regatta mit unserer kostenlosen Tracking-App oder einem professionellen Tracking-Service* durch. (unten: *Wie Trac Trac) Manövererkennung und Analyse
features_events_with_more_regatta_title=Veranstaltungen mit mehr als einer Regatta
features_events_with_more_regatta_description=-
features_events_with_more_regatta_description=Einrichten von Veranstaltungen in mehreren Klassen sowie von Saison-Wertungen wie z.B. bei Segelligen
features_connect_to_tractrac_title=Mit Trac Trac verbinden
features_connect_to_tractrac_description=Verbinden Sie sich mit einem professionellen Tracking-Service
features_imports_title=Externe Daten importieren
features_imports_description=GPX- und KML-Dateiformate importieren
features_imports_description=GPX- und KML-Dateiformate, GRIB-Dateien und Expedition-Protokolldateien importieren
features_media_management_title=Media Management
features_media_management_description=Integrieren/hochladen und wiedergeben von Videos und Bildern
features_analytic_charts_title=Analysediagramme
features_analytic_charts_description=...
features_analytic_charts_description=Diagramme zum Vergleich mehrerer Teilnehmer, Windhistorie sowie Manövertabelle
features_media_tags_title=Medien verlinken und hochladen (Tags)
features_media_tags_description=-
features_media_tags_description=Kommentare und Bilder mit der Zeitleiste verknüpfen und teilen
features_scoring_title=Scoring
features_scoring_description=ORC PCS Wertungen
trial_premium_name=Trial
trial_premium_description=Eine kurze Kostprobe der Premiummitgliedschaft. Läuft einen Tag.
trial_premium_info=Alles vom kostenlosen Plan plus:
trial_premium_price_info
trial_premium_features=\
Vollständige Live-Analyse mit Hunderten von Funktionen, einschließlich Windströmungen, Vergleichstabellen, \
erweiterte In-Map-Visualisierungen und vieles mehr. Siehe die vollständige Liste der Premiumfunktionen unten, \
Kennzeichnen Sie die persönliche Timeline mit Videos und Notizen
features_scoring_description=Low-Point, High-Point, jeweils mit verschiedenen Varianten zum Tie-Break, außerdem verschiedene Handicap-Optionen mit ToT/ToD sowie ORC Performance Curve Scoring
features_map_analytics_title=Kartenanalyse
features_map_analytics_description=Visualisierung von Windströmungen.
features_simulator_title=Simulator
features_simulator_description=Simulation und Analyse des Geschehens.
features_advanced_leaderboard_info_title=Detaillierte Ranglisteninformationen
features_advanced_leaderboard_info_description=Fortgeschrittenen Analyseinformationen zur Rangliste. Wie Beispielsweise Abstand zum Führenden.
features_competitor_analytics_title=Competitoranalyse
features_competitor_analytics_description=Analyseinformationen zu den Competitoren.
features_advanced_leaderboard_info_description=Fortgeschrittenen Analyseinformationen zur Rangliste, z.B. Abstand zum Führenden, Geschwindigkeit über Grund, Abstand zur Kursmittellinie und Manöver
features_competitor_analytics_title=Teilnehmerranalyse
features_competitor_analytics_description=Analysedigramme zu den Teilnehmern zu verschiedenen Kennzahlen wie Geschwindigkeit, Abstand zum Führenden, Luvgeschwindigkeit und Winkel zum wahren Wind (TWA)
features_maneuver_analytics_title=Manöveranalyse
features_maneuver_analytics_description=-Fortgeschrittene Analyseinformationen zu den durchgeführten Manövern der Competitoren.
features_maneuver_analytics_description=-Fortgeschrittene Analyseinformationen zu den durchgeführten Manövern der Teilnehmer, inklusive Manöververlust, Manöverwinkel und Drehgeschwindigkeit
features_wind_analytics_title=Windanalyse
features_wind_analytics_description=Analyseinformationen zu den gesammelten Winddaten.
features_wind_analytics_description=Analyseinformationen zu den gesammelten Winddaten; farbiges animiertes Karten-Overlay sowie grafischer Verlauf der Historie jeder einzelnen Windquelle
features_data_mining_title=Data Mining
features_data_mining_description=Data Mining über Rennen und Events hinweg. \
Je nach Plantyp nur für Archivserver (alles was unter www.sapsailing.com zu finden ist) \
oder alle Subdomains (z. B. für Ligen, Live-Events oder Vereinsserver)
@@ -23,7 +23,9 @@
pointer-events: none;
}
.premium-permitted .premium-container .premium-check-box input {
box-shadow: -1px 1px #ffffff, -3px 3px #d2af25;
-moz-box-shadow: -1px 1px 0 0 #ffffff, -3px 3px 0 0 #d2af25;
-webkit-box-shadow: -1px 1px 0 0 #ffffff, -3px 3px 0 0 #d2af25;
box-shadow: -1px 1px 0 0 #ffffff, -3px 3px 0 0 #d2af25;
}
.premium-container .premium-icon {
width: 17px;
@@ -25,5 +25,6 @@ public interface SubscriptionService extends RemoteService {
SubscriptionPlanDTO getSubscriptionPlanDTOById(String planId);
boolean isUserInPossessionOfRoles(String planId) throws UserManagementException;
String getSelfServicePortalSession();
}
@@ -18,5 +18,7 @@ public interface SubscriptionServiceAsync<C, P> {
public void getSubscriptionPlanDTOById(String planId, AsyncCallback<SubscriptionPlanDTO> callback);
void isUserInPossessionOfRoles(String planId, AsyncCallback<Boolean> callback);
void getSelfServicePortalSession(AsyncCallback<String> accessLink);
}
@@ -3,6 +3,7 @@ package com.sap.sse.security.ui.server.subscription;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
@@ -35,6 +36,7 @@ import com.sap.sse.security.shared.impl.Role;
import com.sap.sse.security.shared.impl.User;
import com.sap.sse.security.shared.subscription.Subscription;
import com.sap.sse.security.shared.subscription.SubscriptionPlan;
import com.sap.sse.security.shared.subscription.SubscriptionPrice;
import com.sap.sse.security.subscription.SubscriptionApiService;
import com.sap.sse.security.ui.client.subscription.SubscriptionService;
import com.sap.sse.security.ui.server.Activator;
@@ -66,9 +68,14 @@ public abstract class SubscriptionServiceImpl extends RemoteServiceServlet imple
public ArrayList<String> getUnlockingSubscriptionplans(WildcardPermission permission)
throws UserManagementException {
final ArrayList<String> result = new ArrayList<>();
final User currentUser = getCurrentUser();
final User currentUser;
if (getSecurityService().getCurrentUser() != null) {
currentUser = getSecurityService().getCurrentUser();
} else {
currentUser = getSecurityService().getAllUser();
}
final SecurityService securityServiceInstance = getSecurityService();
User allUser = securityServiceInstance.getUserByName(SecurityService.ALL_USERNAME);
User allUser = getSecurityService().getAllUser();
getSecurityService().getAllSubscriptionPlans().values().forEach((plan) -> {
final Role[] subscriptionPlanUserRolesArray = getSecurityService().getSubscriptionPlanUserRoles(currentUser, plan);
final Set<Role> subscriptionPlanUserRoles = Stream.of(subscriptionPlanUserRolesArray).collect(Collectors.toSet());
@@ -216,7 +223,7 @@ public abstract class SubscriptionServiceImpl extends RemoteServiceServlet imple
if(isUserSubscribedToPlan) {
isUserSubscribedToPlanCategory = true;
hasHadSubscriptionForOneTimePlan = plan.getIsOneTimePlan();
}else {
} else {
for (SubscriptionPlan subscriptionPlan : getSecurityService().getAllSubscriptionPlans().values()) {
if(isUserSubscribedToPlan(subscriptionPlan.getId())
&& Util.containsAny(plan.getPlanCategories(), subscriptionPlan.getPlanCategories())) {
@@ -231,8 +238,14 @@ public abstract class SubscriptionServiceImpl extends RemoteServiceServlet imple
hasHadSubscriptionForOneTimePlan = false;
}
}
return new SubscriptionPlanDTO(plan.getId(), isUserSubscribedToPlan, plan.getPrices(),
plan.getPlanCategories(), hasHadSubscriptionForOneTimePlan, isUserSubscribedToPlanCategory, null);
final boolean disablePrice = hasHadSubscriptionForOneTimePlan;
Set<SubscriptionPrice> prices = new HashSet<>();
plan.getPrices().forEach(price -> {
price.setDisablePlan(disablePrice);
prices.add(price);
});
return new SubscriptionPlanDTO(plan.getId(), isUserSubscribedToPlan, prices,
plan.getPlanCategories(), hasHadSubscriptionForOneTimePlan, isUserSubscribedToPlanCategory, null, plan.getGroup());
}
private boolean isUserSubscribedToPlan(String planId) {
@@ -3,9 +3,11 @@ package com.sap.sse.security.ui.server.subscription.chargebee;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.chargebee.models.PortalSession;
import com.sap.sse.security.shared.impl.User;
import com.sap.sse.security.shared.subscription.Subscription;
import com.sap.sse.security.shared.subscription.SubscriptionPlan;
@@ -85,4 +87,22 @@ public class ChargebeeSubscriptionServiceImpl extends SubscriptionServiceImpl im
final SubscriptionPlan subscriptionPlanById = getSecurityService().getSubscriptionPlanById(planId);
return subscriptionPlanById == null ? null : convertToDto(subscriptionPlanById);
}
@Override
public String getSelfServicePortalSession() {
try {
User currentUser = getCurrentUser();
CompletableFuture<PortalSession> result = new CompletableFuture<>();
getApiService().getUserSelfServicePortalSession(currentUser.getId().toString(), (session) -> result.complete(session));
final PortalSession portalSession = result.get();
if(portalSession != null) {
return portalSession.accessUrl();
}else {
return null;
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error in getting session", e);
return null;
}
}
}
@@ -10,7 +10,8 @@ public interface HasSubscriptionMessageKeys{
String getSubscriptionPlanId();
default public String getSubscriptionPlanNameMessageKey() {
return getSubscriptionPlanId() + NAME_MESSAGE_KEY_SUFFX;
final String subscriptionPlanId = getSubscriptionPlanId();
return subscriptionPlanId.substring(subscriptionPlanId.indexOf("_") + 1) + NAME_MESSAGE_KEY_SUFFX;
}
default public String getSubscriptionPlanDescMessageKey() {
@@ -6,6 +6,7 @@ import java.util.Set;
import com.google.gwt.user.client.rpc.IsSerializable;
import com.sap.sse.security.shared.subscription.SubscriptionPrice;
import com.sap.sse.security.shared.subscription.SubscriptionPlan.PlanCategory;
import com.sap.sse.security.shared.subscription.SubscriptionPlan.PlanGroup;
import com.sap.sse.security.ui.client.subscription.SubscriptionService;
/**
@@ -20,6 +21,7 @@ public class SubscriptionPlanDTO implements HasSubscriptionMessageKeys, IsSerial
private Set<PlanCategory> planCategory;
private Boolean userWasAlreadySubscribedToOneTimePlan;
private Boolean isUserSubscribedToPlanCategory;
private PlanGroup group;
/**
* For GWT Serialization only
@@ -30,7 +32,7 @@ public class SubscriptionPlanDTO implements HasSubscriptionMessageKeys, IsSerial
public SubscriptionPlanDTO(String id, boolean isUserSubscribedToPlan, Set<SubscriptionPrice> prices,
Set<PlanCategory> planCategory, boolean userWasAlreadySubscribedToOneTimePlan,
boolean isUserSubscribedToPlanCategory, String error) {
boolean isUserSubscribedToPlanCategory, String error, PlanGroup group) {
this.id = id;
this.isUserSubscribedToPlan = isUserSubscribedToPlan;
this.planCategory = planCategory;
@@ -38,6 +40,11 @@ public class SubscriptionPlanDTO implements HasSubscriptionMessageKeys, IsSerial
this.isUserSubscribedToPlanCategory = isUserSubscribedToPlanCategory;
this.prices = new HashSet<SubscriptionPrice>(prices);
this.error = error;
this.group = group;
}
public PlanGroup getGroup() {
return group;
}
public Set<PlanCategory> getPlanCategory() {