001/*
002 * (C) Copyright 2013-2015 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nuxeo - initial API and implementation
018 */
019package org.nuxeo.ecm.platform.ui.web.auth.service;
020
021import java.io.Serializable;
022import java.util.ArrayList;
023import java.util.List;
024
025import javax.ws.rs.core.UriBuilder;
026
027import org.apache.commons.lang.StringUtils;
028
029import org.nuxeo.common.Environment;
030import org.nuxeo.common.xmap.XMap;
031import org.nuxeo.common.xmap.annotation.XNode;
032import org.nuxeo.common.xmap.annotation.XNodeList;
033import org.nuxeo.common.xmap.annotation.XObject;
034import org.nuxeo.runtime.api.Framework;
035
036/**
037 * {@link XMap} object to manage configuration of the login screen (login.jsp)
038 *
039 * @author <a href="mailto:tdelprat@nuxeo.com">Tiry</a>
040 * @since 5.7
041 */
042@XObject("loginScreenConfig")
043public class LoginScreenConfig implements Serializable {
044
045    private static final long serialVersionUID = 1L;
046
047    @XNodeList(value = "loginProviders/loginProvider", type = ArrayList.class, componentType = LoginProviderLink.class)
048    protected List<LoginProviderLink> providers;
049
050    /**
051     * @since 7.10
052     */
053    @XNodeList(value = "videos/video", type = ArrayList.class, componentType = LoginVideo.class)
054    protected List<LoginVideo> videos;
055
056    /**
057     * @since 7.10
058     */
059    @XNode("videos@muted")
060    protected Boolean muted;
061
062    /**
063     * @since 7.10
064     */
065    @XNode("videos@loop")
066    protected Boolean loop;
067
068    /**
069     * @since 7.10
070     */
071    protected String backgroundImage;
072
073    @XNode("removeNews")
074    protected Boolean removeNews = false;
075
076    protected String headerStyle;
077
078    protected String footerStyle;
079
080    protected String newsIframeUrl = "//www.nuxeo.com/standalone-login-page/";
081
082    protected String newsIframeFullUrl = null;
083
084    protected String bodyBackgroundStyle;
085
086    protected String loginBoxBackgroundStyle;
087
088    @XNode("loginBoxWidth")
089    protected String loginBoxWidth;
090
091    protected String logoUrl;
092
093    @XNode("logoAlt")
094    protected String logoAlt;
095
096    @XNode("logoWidth")
097    protected String logoWidth;
098
099    @XNode("logoHeight")
100    protected String logoHeight;
101
102    /**
103     * @since 7.10
104     */
105    @XNode("fieldAutocomplete")
106    protected Boolean fieldAutocomplete;
107
108    /**
109     * Boolean to disable background-cover CSS behavior on login page background, as it may not be compliant with all
110     * browsers (see NXP-12972/NXP-12978).
111     *
112     * @since 5.8
113     */
114    @XNode("disableBackgroundSizeCover")
115    protected Boolean disableBackgroundSizeCover;
116
117    /**
118     * @since 7.10
119     */
120    @XNode("loginButtonBackgroundColor")
121    protected String loginButtonBackgroundColor;
122
123    public LoginScreenConfig() {
124    }
125
126    public List<LoginProviderLink> getProviders() {
127        return providers;
128    }
129
130    public void setProviders(List<LoginProviderLink> providers) {
131        this.providers = providers;
132    }
133
134    public LoginProviderLink getProvider(String name) {
135        if (getProviders() == null) {
136            return null;
137        }
138        for (LoginProviderLink provider : getProviders()) {
139            if (name.equals(provider.getName())) {
140                return provider;
141            }
142        }
143        return null;
144    }
145
146    public void registerLoginProvider(String name, String iconUrl, String link, String label, String description,
147            LoginProviderLinkComputer computer) {
148        LoginProviderLink newProvider = new LoginProviderLink();
149        newProvider.name = name;
150        newProvider.iconPath = iconUrl;
151        newProvider.link = link;
152        newProvider.label = label;
153        newProvider.description = description;
154        if (computer != null) {
155            newProvider.urlComputer = computer;
156        }
157
158        LoginProviderLink existingProvider = getProvider(name);
159        if (existingProvider != null) {
160            existingProvider.merge(newProvider);
161        } else {
162            if (providers == null) {
163                providers = new ArrayList<>();
164            }
165            providers.add(newProvider);
166        }
167    }
168
169    public String getHeaderStyle() {
170        return headerStyle;
171    }
172
173    public String getFooterStyle() {
174        return footerStyle;
175    }
176
177    public String getBodyBackgroundStyle() {
178        return bodyBackgroundStyle;
179    }
180
181    public String getLoginBoxBackgroundStyle() {
182        return loginBoxBackgroundStyle;
183    }
184
185    public String getLoginBoxWidth() {
186        return loginBoxWidth;
187    }
188
189    public String getLogoUrl() {
190        return logoUrl;
191    }
192
193    public String getLogoAlt() {
194        return logoAlt;
195    }
196
197    public String getLogoWidth() {
198        return logoWidth;
199    }
200
201    public String getLogoHeight() {
202        return logoHeight;
203    }
204
205    public List<LoginVideo> getVideos() {
206        return videos;
207    }
208
209    public Boolean getVideoMuted() {
210        return muted == null ? false : muted;
211    }
212
213    public Boolean getVideoLoop() {
214        return loop == null ? true : loop;
215    }
216
217    public boolean hasVideos() {
218        return videos != null && !videos.isEmpty();
219    }
220
221    public boolean getDisplayNews() {
222        return !(removeNews || StringUtils.isBlank(newsIframeUrl));
223    }
224
225    public Boolean getFieldAutocomplete() {
226        return fieldAutocomplete == null ? true : fieldAutocomplete;
227    }
228
229    @XNode("headerStyle")
230    public void setHeaderStyle(String headerStyle) {
231        this.headerStyle = Framework.expandVars(headerStyle);
232    }
233
234    @XNode("footerStyle")
235    public void setFooterStyle(String footerStyle) {
236        this.footerStyle = Framework.expandVars(footerStyle);
237    }
238
239    @XNode("bodyBackgroundStyle")
240    public void setBodyBackgroundStyle(String bodyBackgroundStyle) {
241        this.bodyBackgroundStyle = Framework.expandVars(bodyBackgroundStyle);
242    }
243
244    @XNode("backgroundImage")
245    public void setBackgroundImage(String backgroundImage) {
246        this.backgroundImage = Framework.expandVars(backgroundImage);
247    }
248
249    public String getBackgroundImage() {
250        return this.backgroundImage;
251    }
252
253    public String getLoginButtonBackgroundColor() {
254        return loginButtonBackgroundColor;
255    }
256
257    @XNode("loginBoxBackgroundStyle")
258    public void setLoginBoxBackgroundStyle(String loginBoxBackgroundStyle) {
259        this.loginBoxBackgroundStyle = Framework.expandVars(loginBoxBackgroundStyle);
260    }
261
262    @XNode("logoUrl")
263    public void setLogoUrl(String logoUrl) {
264        this.logoUrl = Framework.expandVars(logoUrl);
265    }
266
267    /**
268     * @since 7.10
269     */
270    @XNode("newsIframeUrl")
271    public void setNewsIframeUrl(String newsIframeUrl) {
272        this.newsIframeUrl = newsIframeUrl;
273        newsIframeFullUrl = null;
274    }
275
276    public String getNewsIframeUrl() {
277        if (newsIframeFullUrl == null) {
278            newsIframeFullUrl = UriBuilder.fromPath(newsIframeUrl)
279                                          .queryParam(Environment.PRODUCT_VERSION,
280                                                  Framework.getProperty(Environment.PRODUCT_VERSION))
281                                          .queryParam(Environment.DISTRIBUTION_VERSION,
282                                                  Framework.getProperty(Environment.DISTRIBUTION_VERSION))
283                                          .build()
284                                          .toString();
285        }
286        return newsIframeFullUrl;
287    }
288
289    /**
290     * @since 5.8
291     * @see #disableBackgroundSizeCover
292     */
293    public Boolean getDisableBackgroundSizeCover() {
294        return disableBackgroundSizeCover;
295    }
296
297    protected void merge(LoginScreenConfig newConfig) {
298        if (newConfig.newsIframeUrl != null) {
299            setNewsIframeUrl(newConfig.newsIframeUrl);
300        }
301        if (newConfig.headerStyle != null) {
302            headerStyle = newConfig.headerStyle;
303        }
304        if (newConfig.footerStyle != null) {
305            footerStyle = newConfig.footerStyle;
306        }
307        if (newConfig.bodyBackgroundStyle != null) {
308            bodyBackgroundStyle = newConfig.bodyBackgroundStyle;
309        }
310        if (newConfig.loginBoxBackgroundStyle != null) {
311            loginBoxBackgroundStyle = newConfig.loginBoxBackgroundStyle;
312        }
313        if (newConfig.loginBoxWidth != null) {
314            loginBoxWidth = newConfig.loginBoxWidth;
315        }
316        if (newConfig.disableBackgroundSizeCover != null) {
317            disableBackgroundSizeCover = newConfig.disableBackgroundSizeCover;
318        }
319        if (newConfig.logoAlt != null) {
320            logoAlt = newConfig.logoAlt;
321        }
322        if (newConfig.logoHeight != null) {
323            logoHeight = newConfig.logoHeight;
324        }
325        if (newConfig.logoUrl != null) {
326            logoUrl = newConfig.logoUrl;
327        }
328        if (newConfig.logoWidth != null) {
329            logoWidth = newConfig.logoWidth;
330        }
331        if (newConfig.fieldAutocomplete != null) {
332            fieldAutocomplete = newConfig.fieldAutocomplete;
333        }
334        if (newConfig.videos != null) {
335            videos = newConfig.videos;
336        }
337        if (newConfig.loop != null) {
338            loop = newConfig.loop;
339        }
340        if (newConfig.removeNews) {
341            removeNews = newConfig.removeNews;
342        }
343        if (newConfig.muted != null) {
344            muted = newConfig.muted;
345        }
346        if (newConfig.loginButtonBackgroundColor != null) {
347            loginButtonBackgroundColor = newConfig.loginButtonBackgroundColor;
348        }
349        if (newConfig.backgroundImage != null) {
350            backgroundImage = newConfig.backgroundImage;
351        }
352
353        if (providers == null) {
354            providers = newConfig.providers;
355        } else if (newConfig.providers != null && newConfig.providers.size() > 0) {
356            for (LoginProviderLink link : newConfig.providers) {
357
358                int idx = providers.indexOf(link);
359                if (idx >= 0) {
360                    if (link.remove) {
361                        providers.remove(idx);
362                    } else {
363                        providers.get(idx).merge(link);
364                    }
365                } else {
366                    providers.add(link);
367                }
368            }
369        }
370    }
371
372    /**
373     * @since 7.10
374     */
375    @Override
376    public LoginScreenConfig clone() {
377        LoginScreenConfig clone = new LoginScreenConfig();
378        clone.bodyBackgroundStyle = bodyBackgroundStyle;
379        clone.disableBackgroundSizeCover = disableBackgroundSizeCover;
380        clone.fieldAutocomplete = fieldAutocomplete;
381        clone.footerStyle = footerStyle;
382        clone.headerStyle = headerStyle;
383        clone.loginBoxBackgroundStyle = loginBoxBackgroundStyle;
384        clone.loginBoxWidth = loginBoxWidth;
385        clone.loginButtonBackgroundColor = loginButtonBackgroundColor;
386        clone.logoAlt = logoAlt;
387        clone.logoHeight = logoHeight;
388        clone.logoUrl = logoUrl;
389        clone.logoWidth = logoWidth;
390        clone.loop = loop;
391        clone.muted = muted;
392        clone.newsIframeUrl = newsIframeUrl;
393        if (providers != null) {
394            clone.providers = new ArrayList<LoginProviderLink>();
395            for (LoginProviderLink l : providers) {
396                clone.providers.add(l.clone());
397            }
398        }
399        clone.removeNews = removeNews;
400        if (videos != null) {
401            clone.videos = new ArrayList<LoginVideo>();
402            for (LoginVideo v : videos) {
403                clone.videos.add(v.clone());
404            }
405        }
406        return clone;
407    }
408
409}