getEventForId(String,String,String)   A
last analyzed

Complexity

Conditions 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
c 0
b 0
f 0
dl 0
loc 8
rs 10
eloc 5
1
package unicon.matthews.caliper.service;
2
3
import java.text.SimpleDateFormat;
4
import java.time.LocalDateTime;
5
import java.time.ZoneId;
6
import java.util.*;
7
import java.util.stream.Collectors;
8
9
import org.apache.commons.lang3.StringUtils;
10
import org.springframework.beans.factory.annotation.Autowired;
11
import org.springframework.data.mongodb.core.MongoOperations;
12
import org.springframework.data.mongodb.core.query.Criteria;
0 ignored issues
show
Unused Code introduced by
Remove this unused import 'org.springframework.data.mongodb.core.query.Criteria'.
Loading history...
13
import org.springframework.data.mongodb.core.query.Query;
14
import org.springframework.stereotype.Service;
15
16
import com.google.common.collect.ImmutableList;
17
18
import unicon.matthews.caliper.ClassEventStatistics;
19
import unicon.matthews.caliper.Event;
20
import unicon.matthews.caliper.exception.EventNotFoundException;
21
import unicon.matthews.caliper.service.repository.MongoEvent;
22
import unicon.matthews.caliper.service.repository.MongoEventRepository;
23
import unicon.matthews.common.exception.BadRequestException;
24
import unicon.matthews.oneroster.exception.ResultNotFoundException;
0 ignored issues
show
Unused Code introduced by
Remove this unused import 'unicon.matthews.oneroster.exception.ResultNotFoundException'.
Loading history...
25
import unicon.matthews.tenant.Tenant;
26
import unicon.matthews.tenant.service.repository.TenantRepository;
27
28
import static org.springframework.data.mongodb.core.query.Criteria.where;
29
30
/**
31
 * @author ggilbert
32
 * @author xchopin <[email protected]>
33
 */
34
@Service
35
public class EventService {
36
  private final TenantRepository tenantRepository;
37
  private final MongoEventRepository mongoEventRepository;
38
  private final UserIdConverter userIdConverter;
39
  private final ClassIdConverter classIdConverter;
40
  private final MongoOperations mongoOps;
41
42
  @Autowired
43
  public EventService(
44
          TenantRepository tenantRepository,
45
          MongoEventRepository mongoEventRepository,
46
          UserIdConverter userIdConverter,
47
          ClassIdConverter classIdConverter,
48
          MongoOperations mongoOperations) {
49
    this.tenantRepository = tenantRepository;
50
    this.mongoEventRepository = mongoEventRepository;
51
    this.userIdConverter = userIdConverter;
52
    this.classIdConverter = classIdConverter;
53
    this.mongoOps = mongoOperations;
54
  }
55
  
56
  public static final ImmutableList<String> STUDENT_ROLES_LIST = 
57
		  ImmutableList.of("http://purl.imsglobal.org/vocab/lis/v2/membership#Learner", "student", "Student");
58
  
59
60
  public String save(String tenantId, String orgId, Event toBeSaved) {
61
62
    if (StringUtils.isBlank(toBeSaved.getId())) {
63
      toBeSaved
64
              = new Event.Builder()
65
              .withAction(toBeSaved.getAction())
66
              .withAgent(toBeSaved.getAgent())
67
              .withContext(toBeSaved.getContext())
68
              .withEdApp(toBeSaved.getEdApp())
69
              .withEventTime(toBeSaved.getEventTime() != null ? toBeSaved.getEventTime() : LocalDateTime.now(ZoneId.of("UTC")))
70
              .withFederatedSession(toBeSaved.getFederatedSession())
71
              .withGenerated(toBeSaved.getGenerated())
72
              .withGroup(toBeSaved.getGroup())
73
              .withId(UUID.randomUUID().toString())
74
              .withMembership(toBeSaved.getMembership())
75
              .withObject(toBeSaved.getObject())
76
              .withTarget(toBeSaved.getTarget())
77
              .withType(toBeSaved.getType())
78
              .build();
79
    }
80
81
    Tenant tenant = tenantRepository.findOne(tenantId);
82
83
    MongoEvent mongoEvent
84
            = new MongoEvent.Builder()
85
            .withClassId(classIdConverter.convert(tenant, toBeSaved))
86
            .withEvent(toBeSaved)
87
            .withOrganizationId(orgId)
88
            .withTenantId(tenantId)
89
            .withUserId(userIdConverter.convert(tenant, toBeSaved))
90
            .build();
91
    MongoEvent saved = mongoEventRepository.save(mongoEvent);
92
    return saved.getEvent().getId();
93
  }
94
95
  public Event getEventForId(final String tenantId, final String orgId, final String eventId) {
96
    MongoEvent mongoEvent = mongoEventRepository.findByTenantIdAndOrganizationIdAndEventId(tenantId, orgId, eventId);
97
98
    if (mongoEvent != null) {
99
      return mongoEvent.getEvent();
100
    }
101
102
    return null;
103
  }
104
105
  public Collection<Event> getEvents(final String tenantId, final String orgId) {
106
    Collection<MongoEvent> mongoEvents = mongoEventRepository.findByTenantIdAndOrganizationId(tenantId, orgId);
107
    if (mongoEvents != null && !mongoEvents.isEmpty()) {
108
      return mongoEvents.stream().map(MongoEvent::getEvent).collect(Collectors.toList());
109
    }
110
    return null;
0 ignored issues
show
Code Smell introduced by
When the calling method is expecting a Collection it is (null-)safer to return an empty Collection instead of null.
Loading history...
111
  }
112
113
  public Collection<Event> getEventsForClassAndUser(final String tenantId, final String orgId, final String classId, final String userId) {
114
    Collection<MongoEvent> mongoEvents = mongoEventRepository.findByTenantIdAndOrganizationIdAndClassIdAndUserIdIgnoreCase(tenantId, orgId, classId, userId);
115
    if (mongoEvents != null && !mongoEvents.isEmpty()) {
116
      return mongoEvents.stream().map(MongoEvent::getEvent).collect(Collectors.toList());
117
    }
118
    return null;
0 ignored issues
show
Code Smell introduced by
When the calling method is expecting a Collection it is (null-)safer to return an empty Collection instead of null.
Loading history...
119
  }
120
  
121
  public ClassEventStatistics getEventStatisticsForClass(final String tenantId, final String orgId, final String classId, boolean studentsOnly) {
122
	  
123
    Collection<MongoEvent> mongoEvents;
124
    
125
    if (studentsOnly)
126
        mongoEvents = mongoEventRepository.findByTenantIdAndOrganizationIdAndClassIdAndEventMembershipRolesIn(tenantId, orgId, classId, STUDENT_ROLES_LIST);
127
    else
128
      mongoEvents = mongoEventRepository.findByTenantIdAndOrganizationIdAndClassId(tenantId, orgId, classId);
129
130
131
    if (mongoEvents == null || mongoEvents.isEmpty()) {
132
      // TODO
133
      throw new RuntimeException();
0 ignored issues
show
Best Practice introduced by
Dedicated exceptions should be preferred over throwing the generic Exception.
Loading history...
134
    }
135
136
    Map<String, Long> studentsCounted = mongoEvents.stream()
137
            .collect(Collectors.groupingBy(MongoEvent::getUserId, Collectors.counting()));
138
139
    Map<String, List<MongoEvent>> eventsByStudent = mongoEvents.stream()
140
            .collect(Collectors.groupingBy(MongoEvent::getUserId));
141
142
    Map<String,Map<String, Long>> eventCountGroupedByDateAndStudent = null;
143
144
    if (eventsByStudent != null) {
145
      eventCountGroupedByDateAndStudent = new HashMap<>();
146
      for (String key : eventsByStudent.keySet()) {
0 ignored issues
show
Performance introduced by
When you need both the keys and the value of a Map, iterating over entrySet() instead of keySet() is more readable.
Loading history...
147
        Map<String, Long> eventCountByDate = eventsByStudent.get(key).stream().collect(Collectors.groupingBy(event -> StringUtils.substringBefore(event.getEvent().getEventTime().toString(), "T"), Collectors.counting()));
148
        eventCountGroupedByDateAndStudent.put(key, eventCountByDate);
149
      }
150
    }
151
152
    Map<String, Long> eventCountByDate = mongoEvents.stream().collect(Collectors.groupingBy(event -> StringUtils.substringBefore(event.getEvent().getEventTime().toString(), "T"), Collectors.counting()));
153
154
155
    return new ClassEventStatistics.Builder()
156
    .withClassSourcedId(classId)
157
    .withTotalEvents(mongoEvents.size())
158
    .withTotalStudentEnrollments(studentsCounted.keySet().size())
159
    .withEventCountGroupedByDate(eventCountByDate)
160
    .withEventCountGroupedByDateAndStudent(eventCountGroupedByDateAndStudent)
161
    .build();
162
163
  }
164
165
  /**
166
   * Gets Events for a user given
167
   *
168
   * @param tenantId an id of a tenant
169
   * @param orgId an id of an organization
170
   * @param userId its id
171
   * @param from (optional) date (yyyy-MM-dd hh:mm) greater
172
   * @param to (optional) date (yyyy-MM-dd hh:mm) less
173
   * @return Events or null
174
   */
175
  public Collection<Event> getEventsForUser(final String tenantId, final String orgId, final String userId, final String from, final String to) throws EventNotFoundException, IllegalArgumentException, BadRequestException {
176
    if (StringUtils.isBlank(tenantId) || StringUtils.isBlank(orgId) || StringUtils.isBlank(userId))
177
      throw new IllegalArgumentException();
178
179
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm");
180
    Collection<MongoEvent> mongoEvents;
181
    Query query = new Query();
182
    query.addCriteria(where("userId").is(userId).and("organizationId").is(orgId).and("tenantId").is(tenantId));
183
184
    if (from.isEmpty() && !to.isEmpty()) {
185
      try {
186
        query.addCriteria(where("event.eventTime").lt(dateFormat.parse(to)));
187
      } catch (Exception e) {
188
        throw new BadRequestException("Not able to parse the date, it has to be in the following format: `yyyy-MM-dd hh:mm` ");
189
      }
190
    } else if (!from.isEmpty() && to.isEmpty()) {
191
      try {
192
        query.addCriteria(where("event.eventTime").gt(dateFormat.parse(from)));
193
      } catch (Exception e) {
194
        throw new BadRequestException("Not able to parse the date, it has to be in the following format: `yyyy-MM-dd hh:mm` ");
195
      }
196
    } else if (!from.isEmpty() && !to.isEmpty()) {
197
      try {
198
        query.addCriteria(where("event.eventTime").lt(dateFormat.parse(to)).gt(dateFormat.parse(from)));
199
      } catch (Exception e) {
200
        throw new BadRequestException("Not able to parse the date, it has to be in the following format: `yyyy-MM-dd hh:mm` ");
201
      }
202
    }
203
204
    mongoEvents = mongoOps.find(query, MongoEvent.class);
205
206
    if (mongoEvents != null && !mongoEvents.isEmpty())
207
      return mongoEvents.stream().map(MongoEvent::getEvent).collect(Collectors.toList());
208
209
    throw new EventNotFoundException("Events not found.");
210
  }
211
212
}
213