001/*
002 * (C) Copyright 2016 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
018 */
019
020package org.nuxeo.ecm.user.center.profile.rest;
021
022import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
023import static org.nuxeo.common.utils.DateUtils.toZonedDateTime;
024import static org.nuxeo.ecm.core.io.marshallers.json.document.DocumentModelJsonWriter.ENTITY_TYPE;
025import static org.nuxeo.ecm.core.io.registry.reflect.Instantiations.SINGLETON;
026import static org.nuxeo.ecm.core.io.registry.reflect.Priorities.REFERENCE;
027import static org.nuxeo.ecm.user.center.profile.UserProfileConstants.USER_PROFILE_AVATAR_FIELD;
028import static org.nuxeo.ecm.user.center.profile.UserProfileConstants.USER_PROFILE_BIRTHDATE_FIELD;
029import static org.nuxeo.ecm.user.center.profile.UserProfileConstants.USER_PROFILE_FACET;
030import static org.nuxeo.ecm.user.center.profile.UserProfileConstants.USER_PROFILE_PHONENUMBER_FIELD;
031
032import java.io.Closeable;
033import java.io.IOException;
034import java.io.OutputStream;
035import java.io.Serializable;
036import java.time.format.DateTimeFormatter;
037import java.util.GregorianCalendar;
038
039import javax.inject.Inject;
040
041import org.nuxeo.ecm.core.api.Blob;
042import org.nuxeo.ecm.core.api.DocumentModel;
043import org.nuxeo.ecm.core.api.NuxeoPrincipal;
044import org.nuxeo.ecm.core.api.model.Property;
045import org.nuxeo.ecm.core.io.download.DownloadService;
046import org.nuxeo.ecm.core.io.marshallers.json.OutputStreamWithJsonWriter;
047import org.nuxeo.ecm.core.io.marshallers.json.enrichers.AbstractJsonEnricher;
048import org.nuxeo.ecm.core.io.registry.Writer;
049import org.nuxeo.ecm.core.io.registry.context.RenderingContext;
050import org.nuxeo.ecm.core.io.registry.reflect.Setup;
051import org.nuxeo.ecm.core.schema.SchemaManager;
052import org.nuxeo.ecm.core.schema.types.Field;
053import org.nuxeo.ecm.core.schema.types.Schema;
054import org.nuxeo.ecm.user.center.profile.UserProfileService;
055import org.nuxeo.runtime.services.config.ConfigurationService;
056
057import com.fasterxml.jackson.core.JsonGenerator;
058
059/**
060 * @author <a href="mailto:ak@nuxeo.com">Arnaud Kervern</a>
061 * @since 8.1
062 */
063@Setup(mode = SINGLETON, priority = REFERENCE)
064public class UserProfileEnricher extends AbstractJsonEnricher<NuxeoPrincipal> {
065
066    public static final String NAME = "userprofile";
067
068    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
069
070    /**
071     * @since 9.3
072     */
073    public static final String COMPATIBILITY_CONFIGURATION_PARAM = "nuxeo.userprofile.enricher.compatibility";
074
075    @Inject
076    protected SchemaManager schemaManager;
077
078    @Inject
079    protected UserProfileService userProfileService;
080
081    @Inject
082    protected ConfigurationService configurationService;
083
084    @Inject
085    protected DownloadService downloadService;
086
087    public UserProfileEnricher() {
088        super(NAME);
089    }
090
091    @Override
092    public void write(JsonGenerator jg, NuxeoPrincipal nuxeoPrincipal) throws IOException {
093        try (RenderingContext.SessionWrapper sw = ctx.getSession(null)) {
094            DocumentModel up = userProfileService.getUserProfileDocument(nuxeoPrincipal.getName(), sw.getSession());
095            jg.writeFieldName(NAME);
096            if (up == null) {
097                jg.writeNull();
098                return;
099            }
100
101            jg.writeStartObject();
102            if (configurationService.isBooleanTrue(COMPATIBILITY_CONFIGURATION_PARAM)) {
103                writeCompatibilityUserProfile(jg, up);
104            } else {
105                writeUserProfile(jg, up);
106            }
107            jg.writeEndObject();
108        }
109    }
110
111    protected void writeCompatibilityUserProfile(JsonGenerator jg, DocumentModel up) throws IOException {
112        Serializable propertyValue = up.getPropertyValue(USER_PROFILE_BIRTHDATE_FIELD);
113        jg.writeStringField("birthdate",
114                propertyValue == null ? null : FORMATTER.format(toZonedDateTime((GregorianCalendar) propertyValue)));
115        jg.writeStringField("phonenumber", (String) up.getPropertyValue(USER_PROFILE_PHONENUMBER_FIELD));
116        Blob avatar = (Blob) up.getPropertyValue(USER_PROFILE_AVATAR_FIELD);
117        if (avatar != null) {
118            String url = downloadService.getDownloadUrl(up, USER_PROFILE_AVATAR_FIELD, avatar.getFilename());
119            jg.writeStringField("avatar", ctx.getBaseUrl() + url);
120        } else {
121            jg.writeNullField("avatar");
122        }
123    }
124
125    protected void writeUserProfile(JsonGenerator jg, DocumentModel up) throws IOException {
126        Writer<Property> propertyWriter = registry.getWriter(ctx, Property.class, APPLICATION_JSON_TYPE);
127        // provides the user profile document to the property marshaller
128        try (Closeable resource = ctx.wrap().with(ENTITY_TYPE, up).open()) {
129            for (Schema schema : schemaManager.getFacet(USER_PROFILE_FACET).getSchemas()) {
130                for (Field field : schema.getFields()) {
131                    jg.writeFieldName(field.getName().getLocalName());
132                    Property property = up.getProperty(field.getName().getPrefixedName());
133                    OutputStream out = new OutputStreamWithJsonWriter(jg);
134                    propertyWriter.write(property, Property.class, Property.class, APPLICATION_JSON_TYPE, out);
135                }
136            }
137        }
138    }
139}