Расчет таблицы рейтинга

This commit is contained in:
upagge 2020-10-01 20:44:01 +03:00
parent f8230a5aa8
commit 892cb7bed1
No known key found for this signature in database
GPG Key ID: 15CD012E46F6BA34
16 changed files with 326 additions and 33 deletions

View File

@ -0,0 +1,25 @@
package org.sadtech.bot.vcs.bitbucket.app.scheduler;
/**
* // TODO: 01.10.2020 Добавить описание.
*
* @author upagge 01.10.2020
*/
import lombok.RequiredArgsConstructor;
import org.sadtech.bot.vcs.core.service.RatingService;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
public class RatingScheduler {
private final RatingService ratingService;
@Scheduled(cron = "0 */1 * * * *")
private void ratingRecalculation() {
ratingService.ratingRecalculation();
}
}

View File

@ -25,7 +25,7 @@ bitbucketbot:
comment-count: 100 comment-count: 100
init: init:
start-comment-id: 8157 start-comment-id: 8157
use: false use: true
bitbucket: bitbucket:
token: ${BITBUCKET_ADMIN_TOKEN} token: ${BITBUCKET_ADMIN_TOKEN}
url-pull-request-open: http://192.168.236.164:7990/rest/api/1.0/dashboard/pull-requests?limit=150&state=OPEN url-pull-request-open: http://192.168.236.164:7990/rest/api/1.0/dashboard/pull-requests?limit=150&state=OPEN

View File

@ -22,4 +22,19 @@
</createTable> </createTable>
</changeSet> </changeSet>
<changeSet id="2020-10-01-create-table-rating-list" author="upagge">
<createTable tableName="rating_list">
<column name="login" type="varchar(64)">
<constraints nullable="false" foreignKeyName="rating_list_login_person_login"
references="person(login)"/>
</column>
<column name="number" type="integer">
<constraints nullable="false" unique="true"/>
</column>
<column name="points" type="integer">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
</databaseChangeLog> </databaseChangeLog>

View File

@ -1,31 +1,42 @@
//package org.sadtech.bot.vcs.core.domain.entity; package org.sadtech.bot.vcs.core.domain.entity;
//
//import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
//import lombok.Getter; import lombok.Getter;
//import lombok.Setter; import lombok.Setter;
// import org.jetbrains.annotations.NotNull;
//import javax.persistence.Column;
//import javax.persistence.Entity; import javax.persistence.Column;
//import javax.persistence.Table; import javax.persistence.Entity;
// import javax.persistence.Id;
///** import javax.persistence.Table;
// * // TODO: 01.10.2020 Добавить описание.
// * /**
// * @author upagge 01.10.2020 * // TODO: 01.10.2020 Добавить описание.
// */ *
// * @author upagge 01.10.2020
//@Getter */
//@Setter
//@Entity @Getter
//@Table(name = "rating_list") @Setter
//@EqualsAndHashCode(onlyExplicitlyIncluded = true) @Entity
//public class RatingList { @Table(name = "rating_list")
// @EqualsAndHashCode(onlyExplicitlyIncluded = true)
// @Column(name = "login") public class RatingList implements Comparable<RatingList> {
// @EqualsAndHashCode.Include
// private String login; @Id
// @Column(name = "login")
// @Column(name = "points") @EqualsAndHashCode.Include
// private Integer points; private String login;
//
//} @Column(name = "points")
private Integer points;
@Column(name = "number")
private Integer number;
@Override
public int compareTo(@NotNull RatingList ratingList) {
return Integer.compare(ratingList.getPoints(), points);
}
}

View File

@ -1,8 +1,12 @@
package org.sadtech.bot.vcs.core.repository; package org.sadtech.bot.vcs.core.repository;
import lombok.NonNull;
import org.sadtech.basic.context.repository.SimpleManagerRepository; import org.sadtech.basic.context.repository.SimpleManagerRepository;
import org.sadtech.bot.vcs.core.domain.entity.RatingHistory; import org.sadtech.bot.vcs.core.domain.entity.RatingHistory;
import java.time.LocalDateTime;
import java.util.List;
/** /**
* // TODO: 01.10.2020 Добавить описание. * // TODO: 01.10.2020 Добавить описание.
* *
@ -10,4 +14,6 @@ import org.sadtech.bot.vcs.core.domain.entity.RatingHistory;
*/ */
public interface RatingHistoryRepository extends SimpleManagerRepository<RatingHistory, Long> { public interface RatingHistoryRepository extends SimpleManagerRepository<RatingHistory, Long> {
List<RatingHistory> findAllByDateAddBetween(@NonNull LocalDateTime from, @NonNull LocalDateTime to);
} }

View File

@ -0,0 +1,24 @@
package org.sadtech.bot.vcs.core.repository;
import org.sadtech.basic.context.repository.SimpleManagerRepository;
import org.sadtech.bot.vcs.core.domain.entity.RatingList;
import java.util.List;
import java.util.Optional;
/**
* // TODO: 01.10.2020 Добавить описание.
*
* @author upagge 01.10.2020
*/
public interface RatingListRepository extends SimpleManagerRepository<RatingList, String> {
Optional<RatingList> getByLogin(String login);
List<RatingList> findFirstThree();
List<RatingList> findLastThree();
long count();
}

View File

@ -1,11 +1,15 @@
package org.sadtech.bot.vcs.core.repository.impl; package org.sadtech.bot.vcs.core.repository.impl;
import lombok.NonNull;
import org.sadtech.basic.database.repository.manager.AbstractSimpleManagerRepository; import org.sadtech.basic.database.repository.manager.AbstractSimpleManagerRepository;
import org.sadtech.bot.vcs.core.domain.entity.RatingHistory; import org.sadtech.bot.vcs.core.domain.entity.RatingHistory;
import org.sadtech.bot.vcs.core.repository.RatingHistoryRepository; import org.sadtech.bot.vcs.core.repository.RatingHistoryRepository;
import org.sadtech.bot.vcs.core.repository.jpa.RatingHistoryJpaRepository; import org.sadtech.bot.vcs.core.repository.jpa.RatingHistoryJpaRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
/** /**
* // TODO: 01.10.2020 Добавить описание. * // TODO: 01.10.2020 Добавить описание.
* *
@ -21,4 +25,9 @@ public class RatingHistoryRepositoryImpl extends AbstractSimpleManagerRepository
this.jpaRepository = jpaRepository; this.jpaRepository = jpaRepository;
} }
@Override
public List<RatingHistory> findAllByDateAddBetween(@NonNull LocalDateTime from, @NonNull LocalDateTime to) {
return jpaRepository.findAllByDateAddBetween(from, to);
}
} }

View File

@ -0,0 +1,53 @@
package org.sadtech.bot.vcs.core.repository.impl;
import org.sadtech.basic.database.repository.manager.AbstractSimpleManagerRepository;
import org.sadtech.bot.vcs.core.domain.entity.RatingList;
import org.sadtech.bot.vcs.core.repository.RatingListRepository;
import org.sadtech.bot.vcs.core.repository.jpa.RatingListJpaRepository;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
/**
* // TODO: 01.10.2020 Добавить описание.
*
* @author upagge 01.10.2020
*/
@Repository
public class RatingListRepositoryImpl extends AbstractSimpleManagerRepository<RatingList, String> implements RatingListRepository {
private final RatingListJpaRepository jpaRepository;
public RatingListRepositoryImpl(RatingListJpaRepository jpaRepository) {
super(jpaRepository);
this.jpaRepository = jpaRepository;
}
@Override
public Optional<RatingList> getByLogin(String login) {
return jpaRepository.findById(login);
}
@Override
public List<RatingList> findFirstThree() {
return jpaRepository.findAll(
PageRequest.of(0, 3, Sort.by(Sort.Direction.ASC, "number"))
).getContent();
}
@Override
public List<RatingList> findLastThree() {
return jpaRepository.findAll(
PageRequest.of(0, 3, Sort.by(Sort.Direction.DESC, "number"))
).getContent();
}
@Override
public long count() {
return jpaRepository.count();
}
}

View File

@ -3,6 +3,9 @@ package org.sadtech.bot.vcs.core.repository.jpa;
import org.sadtech.bot.vcs.core.domain.entity.RatingHistory; import org.sadtech.bot.vcs.core.domain.entity.RatingHistory;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import java.time.LocalDateTime;
import java.util.List;
/** /**
* // TODO: 01.10.2020 Добавить описание. * // TODO: 01.10.2020 Добавить описание.
* *
@ -10,4 +13,6 @@ import org.springframework.data.jpa.repository.JpaRepository;
*/ */
public interface RatingHistoryJpaRepository extends JpaRepository<RatingHistory, Long> { public interface RatingHistoryJpaRepository extends JpaRepository<RatingHistory, Long> {
List<RatingHistory> findAllByDateAddBetween(LocalDateTime from, LocalDateTime to);
} }

View File

@ -0,0 +1,13 @@
package org.sadtech.bot.vcs.core.repository.jpa;
import org.sadtech.bot.vcs.core.domain.entity.RatingList;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* // TODO: 01.10.2020 Добавить описание.
*
* @author upagge 01.10.2020
*/
public interface RatingListJpaRepository extends JpaRepository<RatingList, String> {
}

View File

@ -12,4 +12,8 @@ public interface RatingService {
void addRating(@NonNull String login, @NonNull PointType type, @NonNull Integer points); void addRating(@NonNull String login, @NonNull PointType type, @NonNull Integer points);
void ratingRecalculation();
String getRatingTop(@NonNull String login);
} }

View File

@ -4,11 +4,19 @@ import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.sadtech.bot.vcs.core.domain.PointType; import org.sadtech.bot.vcs.core.domain.PointType;
import org.sadtech.bot.vcs.core.domain.entity.RatingHistory; import org.sadtech.bot.vcs.core.domain.entity.RatingHistory;
import org.sadtech.bot.vcs.core.domain.entity.RatingList;
import org.sadtech.bot.vcs.core.exception.NotFoundException;
import org.sadtech.bot.vcs.core.repository.RatingHistoryRepository; import org.sadtech.bot.vcs.core.repository.RatingHistoryRepository;
import org.sadtech.bot.vcs.core.repository.RatingListRepository;
import org.sadtech.bot.vcs.core.service.RatingService; import org.sadtech.bot.vcs.core.service.RatingService;
import org.sadtech.bot.vcs.core.utils.Smile;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/** /**
* // TODO: 01.10.2020 Добавить описание. * // TODO: 01.10.2020 Добавить описание.
@ -20,6 +28,7 @@ import java.time.LocalDateTime;
public class RatingServiceImpl implements RatingService { public class RatingServiceImpl implements RatingService {
private final RatingHistoryRepository ratingHistoryRepository; private final RatingHistoryRepository ratingHistoryRepository;
private final RatingListRepository ratingListRepository;
@Override @Override
public void addRating(@NonNull String login, @NonNull PointType type, @NonNull Integer points) { public void addRating(@NonNull String login, @NonNull PointType type, @NonNull Integer points) {
@ -31,4 +40,67 @@ public class RatingServiceImpl implements RatingService {
ratingHistoryRepository.save(ratingHistory); ratingHistoryRepository.save(ratingHistory);
} }
@Override
public void ratingRecalculation() {
AtomicInteger i = new AtomicInteger();
final List<RatingList> newRatingList = ratingHistoryRepository.findAllByDateAddBetween(LocalDateTime.now().minusDays(30L), LocalDateTime.now()).stream()
.collect(Collectors.groupingBy(RatingHistory::getLogin, Collectors.summingInt(RatingHistory::getPoints)))
.entrySet().stream()
.map(this::createRatingList)
.sorted()
.peek(ratingList -> ratingList.setNumber(i.getAndIncrement()))
.collect(Collectors.toList());
ratingListRepository.saveAll(newRatingList);
}
private RatingList createRatingList(Map.Entry<String, Integer> entry) {
final RatingList ratingList = new RatingList();
ratingList.setLogin(entry.getKey());
ratingList.setPoints(entry.getValue());
return ratingList;
}
@Override
public String getRatingTop(@NonNull String login) {
final RatingList personRating = ratingListRepository.getByLogin(login)
.orElseThrow(() -> new NotFoundException("Пользователь не найден"));
final Integer numberRatingList = personRating.getNumber();
final long countPerson = ratingListRepository.count();
final String threeMessage = ratingListRepository.findFirstThree().stream()
.map(this::createString)
.collect(Collectors.joining("\n"));
final String lastMessage = ratingListRepository.findLastThree().stream()
.map(this::createString)
.limit(countPerson - 3)
.collect(Collectors.joining("\n"));
String message = threeMessage;
if (numberRatingList <= 2) {
if (countPerson > 3) {
message += "\n... ... ...\n";
}
} else if (numberRatingList > 3 && numberRatingList <= (countPerson - 3)) {
message += "\n... ... ...\n" + personRating.getNumber() + ": " + personRating.getLogin() + "\n... ... ...\n";
} else {
message += "\n... ... ...\n";
}
message += lastMessage;
return message;
}
private String createString(RatingList ratingList) {
String message = "";
final Integer number = ratingList.getNumber();
if (number == 0) {
message += Smile.TOP_ONE + " " + ratingList.getLogin() + " " + Smile.TOP_ONE;
} else if (number == 1) {
message += Smile.TOP_TWO + " " + ratingList.getLogin() + " " + Smile.TOP_TWO;
} else if (number == 2) {
message += Smile.TOP_THREE + " " + ratingList.getLogin() + " " + Smile.TOP_THREE;
} else {
message += Smile.KAKASHKA + " " + ratingList.getLogin();
}
return message;
}
} }

View File

@ -27,6 +27,10 @@ public enum Smile {
DAY_4("\uD83C\uDF11"), DAY_4("\uD83C\uDF11"),
DAY_5("\uD83C\uDF1A"), DAY_5("\uD83C\uDF1A"),
TASK("\uD83D\uDCBC"), TASK("\uD83D\uDCBC"),
TOP_ONE("\uD83C\uDF1F\uD83C\uDF1F\uD83C\uDF1F"),
TOP_TWO("\uD83D\uDE0E"),
TOP_THREE("\uD83E\uDD49"),
KAKASHKA("\uD83D\uDCA9"),
MEGA_FUN("\uD83D\uDE02"), MEGA_FUN("\uD83D\uDE02"),
DANGEROUS("⚠️"), DANGEROUS("⚠️"),
BELL("\uD83D\uDECE"), BELL("\uD83D\uDECE"),

View File

@ -0,0 +1,33 @@
package org.sadtech.bot.vcs.telegram.service.unit;
import lombok.RequiredArgsConstructor;
import org.sadtech.bot.vcs.core.domain.entity.Person;
import org.sadtech.bot.vcs.core.exception.NotFoundException;
import org.sadtech.bot.vcs.core.service.PersonService;
import org.sadtech.bot.vcs.core.service.RatingService;
import org.sadtech.social.bot.service.usercode.ProcessingData;
import org.sadtech.social.core.domain.BoxAnswer;
import org.sadtech.social.core.domain.content.Message;
import org.springframework.stereotype.Component;
/**
* // TODO: 01.10.2020 Добавить описание.
*
* @author upagge 01.10.2020
*/
@Component
@RequiredArgsConstructor
public class RatingTopProcessing implements ProcessingData<Message> {
private final RatingService ratingService;
private final PersonService personService;
@Override
public BoxAnswer processing(Message content) {
final Person person = personService.getByTelegramId(content.getPersonId())
.orElseThrow(() -> new NotFoundException("Пользователь не найден"));
return BoxAnswer.builder()
.message(ratingService.getRatingTop(person.getLogin()))
.build();
}
}

View File

@ -3,6 +3,7 @@ package org.sadtech.bot.vcs.telegram.unit;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.sadtech.bot.vcs.core.service.PersonService; import org.sadtech.bot.vcs.core.service.PersonService;
import org.sadtech.bot.vcs.telegram.service.unit.PullRequestProcessing; import org.sadtech.bot.vcs.telegram.service.unit.PullRequestProcessing;
import org.sadtech.bot.vcs.telegram.service.unit.RatingTopProcessing;
import org.sadtech.bot.vcs.telegram.service.unit.TaskProcessing; import org.sadtech.bot.vcs.telegram.service.unit.TaskProcessing;
import org.sadtech.bot.vcs.telegram.utils.GeneratorKeyBoards; import org.sadtech.bot.vcs.telegram.utils.GeneratorKeyBoards;
import org.sadtech.social.bot.domain.unit.AnswerCheck; import org.sadtech.social.bot.domain.unit.AnswerCheck;
@ -44,7 +45,8 @@ public class UnitConfig {
public AnswerText menu( public AnswerText menu(
AnswerProcessing<Message> getTasks, AnswerProcessing<Message> getTasks,
AnswerProcessing<Message> getPr, AnswerProcessing<Message> getPr,
AnswerText settings AnswerText settings,
AnswerProcessing<Message> getTopRating
) { ) {
return AnswerText.builder() return AnswerText.builder()
.boxAnswer( .boxAnswer(
@ -56,6 +58,7 @@ public class UnitConfig {
.nextUnit(getTasks) .nextUnit(getTasks)
.nextUnit(getPr) .nextUnit(getPr)
.nextUnit(settings) .nextUnit(settings)
.nextUnit(getTopRating)
.build(); .build();
} }
@ -97,6 +100,16 @@ public class UnitConfig {
.build(); .build();
} }
@Bean
AnswerProcessing<Message> getTopRating(
RatingTopProcessing ratingTopProcessing
) {
return AnswerProcessing.builder()
.processingData(ratingTopProcessing)
.keyWord("таблица")
.keyWord("рейтинга")
.build();
}
@Bean @Bean
public AnswerProcessing<Mail> noRegister() { public AnswerProcessing<Mail> noRegister() {

View File

@ -17,6 +17,7 @@ public class GeneratorKeyBoards {
public static KeyBoard menu() { public static KeyBoard menu() {
final KeyBoardButtonText tasks = KeyBoardButtonText.builder().label("Мои задачи").build(); final KeyBoardButtonText tasks = KeyBoardButtonText.builder().label("Мои задачи").build();
final KeyBoardButtonText pr = KeyBoardButtonText.builder().label("Проверить ПР").build(); final KeyBoardButtonText pr = KeyBoardButtonText.builder().label("Проверить ПР").build();
final KeyBoardButtonText top = KeyBoardButtonText.builder().label("\uD83C\uDF1F Таблица рейтинга \uD83C\uDF1F").build();
final KeyBoardButtonText settings = KeyBoardButtonText.builder().label("Настройки").build(); final KeyBoardButtonText settings = KeyBoardButtonText.builder().label("Настройки").build();
final KeyBoardLine oneLine = KeyBoardLine.builder() final KeyBoardLine oneLine = KeyBoardLine.builder()
@ -25,12 +26,17 @@ public class GeneratorKeyBoards {
.build(); .build();
final KeyBoardLine twoLine = KeyBoardLine.builder() final KeyBoardLine twoLine = KeyBoardLine.builder()
.buttonKeyBoard(top)
.build();
final KeyBoardLine threeLine = KeyBoardLine.builder()
.buttonKeyBoard(settings) .buttonKeyBoard(settings)
.build(); .build();
return KeyBoard.builder() return KeyBoard.builder()
.lineKeyBoard(oneLine) .lineKeyBoard(oneLine)
.lineKeyBoard(twoLine) .lineKeyBoard(twoLine)
.lineKeyBoard(threeLine)
.build(); .build();
} }