/*
* Copyright (C) 2015, 2016 WTFDYUM
*
* This file is part of the WTFDYUM project.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeanchampemont.wtfdyum.service.impl;
import com.jeanchampemont.wtfdyum.dto.Event;
import com.jeanchampemont.wtfdyum.dto.Feature;
import com.jeanchampemont.wtfdyum.dto.type.EventType;
import com.jeanchampemont.wtfdyum.dto.type.UserLimitType;
import com.jeanchampemont.wtfdyum.service.FeatureService;
import com.jeanchampemont.wtfdyum.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.time.Clock;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
@Service
public class UserServiceImpl implements UserService {
private static final String EVENTS_KEY_PREFIX = "EVENTS_";
private static final String FEATURES_KEY_PREFIX = "FEATURES_";
@Autowired
public UserServiceImpl(final RedisTemplate<String, Event> eventRedisTemplate,
final RedisTemplate<String, Feature> featureRedisTemplate,
final RedisTemplate<String, Long> longRedisTemplate,
final FeatureService featureService,
final Clock clock) {
this.eventRedisTemplate = eventRedisTemplate;
this.featureRedisTemplate = featureRedisTemplate;
this.longRedisTemplate = longRedisTemplate;
this.featureService = featureService;
this.clock = clock;
}
private final RedisTemplate<String, Event> eventRedisTemplate;
private final RedisTemplate<String, Feature> featureRedisTemplate;
private final RedisTemplate<String, Long> longRedisTemplate;
private final FeatureService featureService;
private final Clock clock;
@Override
public void addEvent(final Long userId, final Event event) {
event.setCreationDateTime(LocalDateTime.now(clock));
eventRedisTemplate.opsForList().leftPush(eventsKey(userId), event);
}
@Override
public boolean applyLimit(final Long userId, final UserLimitType type) {
final boolean reached = longRedisTemplate.opsForValue().increment(limitKey(userId, type), 1L) >= type
.getLimitValue();
if (reached) {
for (final Feature f : Feature.values()) {
featureService.disableFeature(userId, f);
}
addEvent(userId, new Event(EventType.CREDENTIALS_INVALID_LIMIT_REACHED, ""));
}
return reached;
}
@Override
public Set<Feature> getEnabledFeatures(final Long userId) {
return featureRedisTemplate.opsForSet().members(featuresKey(userId));
}
@Override
public List<Event> getRecentEvents(final Long userId, final int count) {
return getRecentEvents(userId, count, 0);
}
@Override
public List<Event> getRecentEvents(Long userId, int count, int start) {
return eventRedisTemplate.opsForList().range(eventsKey(userId), start, start + count);
}
@Override
public void resetLimit(final Long userId, final UserLimitType type) {
longRedisTemplate.delete(limitKey(userId, type));
}
private String eventsKey(final Long userId) {
return new StringBuilder(EVENTS_KEY_PREFIX).append(userId.toString()).toString();
}
private String featuresKey(final Long userId) {
return new StringBuilder(FEATURES_KEY_PREFIX).append(userId.toString()).toString();
}
private String limitKey(final Long userId, final UserLimitType type) {
return new StringBuilder(type.name()).append("_").append(userId.toString()).toString();
}
}