View Javadoc
1   /*
2    * Licensed to The Apereo Foundation under one or more contributor license
3    * agreements. See the NOTICE file distributed with this work for additional
4    * information regarding copyright ownership.
5    *
6    *
7    * The Apereo Foundation licenses this file to you under the Educational
8    * Community License, Version 2.0 (the "License"); you may not use this file
9    * except in compliance with the License. You may obtain a copy of the License
10   * at:
11   *
12   *   http://opensource.org/licenses/ecl2.txt
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
17   * License for the specific language governing permissions and limitations under
18   * the License.
19   *
20   */
21  
22  package org.opencastproject.adminui.usersettings;
23  
24  import static org.opencastproject.db.Queries.namedQuery;
25  
26  import org.opencastproject.adminui.usersettings.persistence.UserSettingDto;
27  import org.opencastproject.adminui.usersettings.persistence.UserSettingsServiceException;
28  import org.opencastproject.db.DBSession;
29  import org.opencastproject.db.DBSessionFactory;
30  import org.opencastproject.security.api.OrganizationDirectoryService;
31  import org.opencastproject.security.api.SecurityService;
32  import org.opencastproject.security.api.UserDirectoryService;
33  
34  import org.apache.commons.lang3.tuple.Pair;
35  import org.osgi.service.component.ComponentContext;
36  import org.osgi.service.component.annotations.Activate;
37  import org.osgi.service.component.annotations.Component;
38  import org.osgi.service.component.annotations.Reference;
39  import org.slf4j.Logger;
40  import org.slf4j.LoggerFactory;
41  
42  import java.util.List;
43  import java.util.function.Function;
44  
45  import javax.persistence.EntityManager;
46  import javax.persistence.EntityManagerFactory;
47  
48  /**
49   * Finds the user settings and message signatures from the current user.
50   */
51  @Component(
52    immediate = true,
53    service = UserSettingsService.class,
54    property = {
55      "service.description=Admin UI - Users Settings Service",
56      "opencast.service.type=org.opencastproject.adminui.usersettings.UserSettingsService"
57    }
58  )
59  public class UserSettingsService {
60    public static final String PERSISTENCE_UNIT = "org.opencastproject.adminui";
61  
62    /** Logging utilities */
63    private static final Logger logger = LoggerFactory.getLogger(UserSettingsService.class);
64  
65    /** Factory used to create {@link EntityManager}s for transactions */
66    protected EntityManagerFactory emf;
67  
68    protected DBSessionFactory dbSessionFactory;
69  
70    protected DBSession db;
71  
72    /** The user directory service */
73    protected UserDirectoryService userDirectoryService;
74  
75    /** The organization directory service */
76    protected OrganizationDirectoryService organizationDirectoryService;
77  
78    /** The security service */
79    protected SecurityService securityService;
80  
81    /**
82     * Creates {@link EntityManagerFactory} using persistence provider and properties passed via OSGi.
83     *
84     * @param cc
85     */
86    @Activate
87    public void activate(ComponentContext cc) {
88      logger.info("Activating persistence manager for user settings");
89      db = dbSessionFactory.createSession(emf);
90    }
91  
92    /** OSGi DI */
93    @Reference(target = "(osgi.unit.name=org.opencastproject.adminui)")
94    public void setEntityManagerFactory(EntityManagerFactory emf) {
95      this.emf = emf;
96    }
97  
98    @Reference
99    public void setDBSessionFactory(DBSessionFactory dbSessionFactory) {
100     this.dbSessionFactory = dbSessionFactory;
101   }
102 
103   /**
104    * OSGi callback to set user directory service.
105    *
106    * @param userDirectoryService
107    *          user directory service
108    */
109   @Reference
110   public void setUserDirectoryService(UserDirectoryService userDirectoryService) {
111     this.userDirectoryService = userDirectoryService;
112   }
113 
114   /**
115    * OSGi callback to set the security service.
116    *
117    * @param securityService
118    *          the security service
119    */
120   @Reference
121   public void setSecurityService(SecurityService securityService) {
122     this.securityService = securityService;
123   }
124 
125   /**
126    * OSGi callback to set the organization directory service.
127    *
128    * @param organizationDirectoryService
129    *          the organization directory service
130    */
131   public void setOrganizationDirectoryService(OrganizationDirectoryService organizationDirectoryService) {
132     this.organizationDirectoryService = organizationDirectoryService;
133   }
134 
135   /**
136    * Finds the user settings for the current user.
137    *
138    * @param limit
139    *          The maximum limit of results to return.
140    * @param offset
141    *          The starting page offset.
142    * @return The user settings for the current user.
143    * @throws UserSettingsServiceException
144    */
145   public UserSettings findUserSettings(int limit, int offset) throws UserSettingsServiceException {
146     try {
147       UserSettings userSettings = db.exec(getUserSettingsQuery(limit, offset));
148       userSettings.setTotal(db.exec(getUserSettingsTotalQuery()));
149       userSettings.setLimit(limit);
150       userSettings.setOffset(offset);
151       return userSettings;
152     } catch (Exception e) {
153       logger.error("Could not get user settings:", e);
154       throw new UserSettingsServiceException(e);
155     }
156   }
157 
158   /**
159    * @return Function that finds the total number of user settings for the current user.
160    */
161   private Function<EntityManager, Integer> getUserSettingsTotalQuery() {
162     String orgId = securityService.getOrganization().getId();
163     String username = securityService.getUser().getUsername();
164     return namedQuery.find(
165         "UserSettings.countByUserName",
166         Number.class,
167         Pair.of("username", username),
168         Pair.of("org", orgId)
169     ).andThen(Number::intValue);
170   }
171 
172   /**
173    * @param offset
174    *          The number of limits to page to.
175    * @param limit
176    *          The maximum number of settings to return.
177    * @return Function that finds all of the user settings for the current user.
178    */
179   private Function<EntityManager, UserSettings> getUserSettingsQuery(int limit, int offset) {
180     return em -> {
181       String orgId = securityService.getOrganization().getId();
182       String username = securityService.getUser().getUsername();
183       logger.debug("Getting user settings for '{}' in org '{}'", username, orgId);
184 
185       List<UserSettingDto> result = em
186           .createNamedQuery("UserSettings.findByUserName", UserSettingDto.class)
187           .setParameter("username", username)
188           .setParameter("org", orgId)
189           .setMaxResults(limit)
190           .setFirstResult(offset)
191           .getResultList();
192       if (result.size() == 0) {
193         logger.debug("Found no user settings.");
194       }
195 
196       UserSettings userSettings = new UserSettings();
197       for (UserSettingDto userSettingsDto : result) {
198         UserSetting userSetting = userSettingsDto.toUserSetting();
199         logger.debug("Found user setting id: {} key: {} value: {}", userSetting.getId(), userSetting.getKey(),
200             userSetting.getValue());
201         userSettings.addUserSetting(userSetting);
202       }
203       return userSettings;
204     };
205   }
206 
207   /**
208    * Create a new user setting key value pair.
209    *
210    * @param key
211    *          The key to use for the current user setting.
212    * @param value
213    *          The value of the user setting.
214    * @return A new user setting object
215    * @throws UserSettingsServiceException
216    */
217   public UserSetting addUserSetting(String key, String value) throws UserSettingsServiceException {
218     String orgId = securityService.getOrganization().getId();
219     String username = securityService.getUser().getUsername();
220     try {
221       return db.execTx(em -> {
222         UserSettingDto userSettingDto = new UserSettingDto();
223         userSettingDto.setKey(key);
224         userSettingDto.setValue(value);
225         userSettingDto.setUsername(username);
226         userSettingDto.setOrganization(orgId);
227         em.persist(userSettingDto);
228         return userSettingDto.toUserSetting();
229       });
230     } catch (Exception e) {
231       logger.error("Could not update user setting username '{}' org: '{}' key: '{}' value: '{}'", username, orgId, key,
232           value, e);
233       throw new UserSettingsServiceException(e);
234     }
235   }
236 
237   /**
238    * Get all user settings based upon its key.
239    * @param key The key to search for.
240    * @return A function returning {@link UserSettingDto} that matches the key.
241    */
242   private Function<EntityManager, List<UserSettingDto>> getUserSettingsByKeyQuery(String key) {
243     String orgId = securityService.getOrganization().getId();
244     String username = securityService.getUser().getUsername();
245     logger.debug("Getting user settings for '{}' in org '{}'", username, orgId);
246     return namedQuery.findAll(
247         "UserSettings.findByKey",
248         UserSettingDto.class,
249         Pair.of("key", key),
250         Pair.of("username", username),
251         Pair.of("org", orgId)
252     );
253   }
254 
255   /**
256    * Update a user setting that currently exists using its key to find it.
257    * @param key The key for the user setting.
258    * @param value The new value to set for the user setting.
259    * @return An updated {@link UserSetting}
260    * @throws UserSettingsServiceException
261    */
262   public UserSetting updateUserSetting(String key, String value, String oldValue) throws UserSettingsServiceException {
263     try {
264       UserSettingDto userSettingDto = db.exec(getUserSettingsByKeyQuery(key)).stream()
265           .filter(setting -> setting.getKey().equalsIgnoreCase(key) && setting.getValue().equalsIgnoreCase(oldValue))
266           .findFirst()
267           .orElseThrow(() -> new UserSettingsServiceException("Unable to find user setting with key " + key + " value "
268               + value + " and old value " + oldValue));
269 
270       return updateUserSetting(userSettingDto.getId(), key, value);
271     } catch (Exception e) {
272       logger.error("Could not update user setting", e);
273       throw new UserSettingsServiceException(e);
274     }
275   }
276 
277   /**
278    * Update a user setting that currently exists using its unique id to find it.
279    * @param id The id for the user setting.
280    * @param key The key for the user setting.
281    * @param value The value for the user setting.
282    * @return The updated {@link UserSetting}.
283    * @throws UserSettingsServiceException
284    */
285   public UserSetting updateUserSetting(long id, String key, String value) throws UserSettingsServiceException {
286     String orgId = securityService.getOrganization().getId();
287     String username = securityService.getUser().getUsername();
288     logger.debug("Updating user setting id: {} key: {} value: {}", id, key, value);
289 
290     try {
291       return db.execTx(em -> {
292         UserSettingDto userSettingDto = em.find(UserSettingDto.class, id);
293         userSettingDto.setKey(key);
294         userSettingDto.setValue(value);
295         em.persist(userSettingDto);
296         return userSettingDto.toUserSetting();
297       });
298     } catch (Exception e) {
299       logger.error("Could not update user setting username '{}' org: '{}' id: '{}' key: '{}' value: '{}'",
300         username, orgId, id, key, value, e);
301       throw new UserSettingsServiceException(e);
302     }
303   }
304 
305   /**
306    * Delete a user setting by using a unique id to find it.
307    *
308    * @param id
309    *          The unique id for the user setting.
310    * @throws UserSettingsServiceException
311    */
312   public void deleteUserSetting(long id) throws UserSettingsServiceException {
313     try {
314       db.execTx(em -> {
315         UserSettingDto userSettingsDto = em.find(UserSettingDto.class, id);
316         em.remove(userSettingsDto);
317       });
318     } catch (Exception e) {
319       logger.error("Could not delete user setting '{}'", id, e);
320       throw new UserSettingsServiceException(e);
321     }
322   }
323 }