View Javadoc
1   package net.sumaris.server.http.graphql.technical;
2   
3   /*-
4    * #%L
5    * SUMARiS:: Server
6    * %%
7    * Copyright (C) 2018 SUMARiS Consortium
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/gpl-3.0.html>.
22   * #L%
23   */
24  
25  import com.fasterxml.jackson.databind.ObjectMapper;
26  import io.leangen.graphql.annotations.GraphQLArgument;
27  import io.leangen.graphql.annotations.GraphQLEnvironment;
28  import io.leangen.graphql.annotations.GraphQLMutation;
29  import io.leangen.graphql.annotations.GraphQLQuery;
30  import net.sumaris.core.service.administration.DepartmentService;
31  import net.sumaris.core.service.technical.SoftwareService;
32  import net.sumaris.core.vo.administration.user.DepartmentVO;
33  import net.sumaris.core.vo.technical.ConfigurationVO;
34  import net.sumaris.core.vo.technical.SoftwareVO;
35  import net.sumaris.server.config.SumarisServerConfiguration;
36  import net.sumaris.server.config.SumarisServerConfigurationOption;
37  import net.sumaris.server.http.graphql.administration.AdministrationGraphQLService;
38  import net.sumaris.server.http.rest.RestPaths;
39  import net.sumaris.server.service.administration.ImageService;
40  import org.apache.commons.collections4.MapUtils;
41  import org.apache.commons.lang3.ArrayUtils;
42  import org.apache.commons.lang3.StringUtils;
43  import org.apache.commons.logging.Log;
44  import org.apache.commons.logging.LogFactory;
45  import org.springframework.beans.factory.annotation.Autowired;
46  import org.springframework.stereotype.Service;
47  import org.springframework.transaction.annotation.Transactional;
48  
49  import java.io.IOException;
50  import java.util.List;
51  import java.util.Objects;
52  import java.util.Set;
53  import java.util.stream.Collectors;
54  import java.util.stream.Stream;
55  
56  @Service
57  @Transactional
58  public class ConfigurationGraphQLService {
59  
60      public static final String JSON_START_SUFFIX = "{";
61  
62      private static final Log log = LogFactory.getLog(ConfigurationGraphQLService.class);
63  
64      @Autowired
65      private SoftwareService service;
66  
67      @Autowired
68      private AdministrationGraphQLService administrationGraphQLService;
69  
70      @Autowired
71      private DepartmentService departmentService;
72  
73      @Autowired
74      private ObjectMapper objectMapper;
75  
76      private String imageUrl;
77  
78      @Autowired
79      public ConfigurationGraphQLService(SumarisServerConfiguration config) {
80          super();
81  
82          // Prepare URL for String formatter
83          imageUrl = config.getServerUrl() + RestPaths.IMAGE_PATH;
84      }
85  
86      @GraphQLQuery(name = "configuration", description = "A software configuration")
87      @Transactional(readOnly = true)
88      public ConfigurationVO getConfiguration(
89              @GraphQLArgument(name = "software") String softwareLabel,
90              @GraphQLEnvironment() Set<String> fields
91      ){
92          SoftwareVO software  = StringUtils.isBlank(softwareLabel) ? service.getDefault() : service.get(softwareLabel);
93          return toConfiguration(software, fields);
94      }
95  
96      @GraphQLMutation(name = "saveConfiguration", description = "Save a software configuration")
97      public ConfigurationVO save(@GraphQLArgument(name = "config") ConfigurationVO configuration,
98                       @GraphQLEnvironment() Set<String> fields){
99  
100         SoftwareVO software = service.save(configuration);
101         return toConfiguration(software, fields);
102     }
103 
104     /* -- protected methods -- */
105 
106     protected ConfigurationVO toConfiguration(SoftwareVO software,  Set<String> fields) {
107         if (software == null) return null;
108         ConfigurationVOonfigurationVO.html#ConfigurationVO">ConfigurationVO result = new ConfigurationVO(software);
109 
110         // Fill partners departments
111         if (fields.contains(ConfigurationVO.Fields.PARTNERS)) {
112             this.fillPartners(result);
113         }
114 
115         // Fill background images URLs
116         if (fields.contains(ConfigurationVO.Fields.BACKGROUND_IMAGES)) {
117             this.fillBackgroundImages(result);
118         }
119 
120         // Fill logo URL
121         String logoUri = getProperty(result, SumarisServerConfigurationOption.SITE_LOGO_SMALL.getKey());
122         if (StringUtils.isNotBlank(logoUri)) {
123             String logoUrl = getImageUrl(logoUri);
124             result.getProperties().put(
125                     SumarisServerConfigurationOption.SITE_LOGO_SMALL.getKey(),
126                     logoUrl);
127             result.setSmallLogo(logoUrl);
128         }
129 
130         // Fill large logo
131         String logoLargeUri = getProperty(result, SumarisServerConfigurationOption.LOGO_LARGE.getKey());
132         if (StringUtils.isNotBlank(logoLargeUri)) {
133             String logoLargeUrl = getImageUrl(logoLargeUri);
134             result.getProperties().put(
135                     SumarisServerConfigurationOption.LOGO_LARGE.getKey(),
136                     logoLargeUrl);
137             result.setLargeLogo(logoLargeUrl);
138         }
139 
140         // Replace favicon ID by an URL
141         String faviconUri = getProperty(result, SumarisServerConfigurationOption.SITE_FAVICON.getKey());
142         if (StringUtils.isNotBlank(faviconUri)) {
143             String faviconUrl = getImageUrl(faviconUri);
144             result.getProperties().put(SumarisServerConfigurationOption.SITE_FAVICON.getKey(), faviconUrl);
145         }
146 
147         return result;
148     }
149 
150     protected String getProperty(ConfigurationVO config, String propertyName) {
151         return MapUtils.getString(config.getProperties(), propertyName);
152     }
153 
154     protected String[] getPropertyAsArray(ConfigurationVO config, String propertyName) {
155         String value = getProperty(config, propertyName);
156 
157         if (StringUtils.isBlank(value)) return null;
158 
159         try {
160             return objectMapper.readValue(value, String[].class);
161         } catch (IOException e) {
162             log.warn(String.format("Unable to deserialize array value for option {%s}: %s", propertyName, value));
163             return value.split(",");
164         }
165     }
166 
167     protected void fillPartners(ConfigurationVO result) {
168         String[] values = getPropertyAsArray(result, SumarisServerConfigurationOption.SITE_PARTNER_DEPARTMENTS.getKey());
169 
170         if (ArrayUtils.isNotEmpty(values)) {
171 
172             // Get department from IDs
173             int[] ids = Stream.of(values)
174                     .map(String::trim)
175                     .mapToInt(uri -> {
176                 if (uri.startsWith(DepartmentService.URI_DEPARTMENT_SUFFIX)) {
177                     return Integer.parseInt(uri.substring(DepartmentService.URI_DEPARTMENT_SUFFIX.length()));
178                 }
179                 return -1;
180             })
181             .filter(id -> id >= 0).toArray();
182             List<DepartmentVO> departments = departmentService.getByIds(ids);
183 
184             // Get department from JSON
185             List<DepartmentVO> deserializeDepartments = Stream.of(values)
186                     .map(String::trim)
187                     .map(jsonStr -> {
188                 if (jsonStr.startsWith(JSON_START_SUFFIX)) {
189                     try {
190                         return objectMapper.readValue(jsonStr, DepartmentVO.class);
191                     } catch(IOException e) {
192                         log.warn(String.format("Unable to deserialize a value for option {%s}: %s", SumarisServerConfigurationOption.SITE_PARTNER_DEPARTMENTS.getKey(), jsonStr), e);
193                         return null;
194                     }
195                 }
196                 return null;
197             }).filter(Objects::nonNull).collect(Collectors.toList());
198 
199             departments = Stream.concat(departments.stream(), deserializeDepartments.stream())
200                     .map(administrationGraphQLService::fillLogo)
201                     .collect(Collectors.toList());
202             result.setPartners(departments);
203         }
204     }
205 
206     protected void fillBackgroundImages(ConfigurationVO result) {
207         String[] values = getPropertyAsArray(result, SumarisServerConfigurationOption.SITE_BACKGROUND_IMAGES.getKey());
208 
209         if (ArrayUtils.isNotEmpty(values)) {
210 
211             List<String> urls = Stream.of(values)
212                     .map(this::getImageUrl)
213                     .collect(Collectors.toList());
214             result.setBackgroundImages(urls);
215         }
216     }
217 
218     protected String getImageUrl(String imageUri) {
219         if (StringUtils.isBlank(imageUri)) return null;
220 
221         // Resolve URI like 'image:<ID>'
222         if (imageUri.startsWith(ImageService.URI_IMAGE_SUFFIX)) {
223             return imageUrl.replace("{id}", imageUri.substring(ImageService.URI_IMAGE_SUFFIX.length()));
224         }
225         // should be a URL, so return it
226         return imageUri;
227     }
228 
229 }