Skip to content

Commit

Permalink
feat: Improve display of rewards detail list - MEED-7632 - Meeds-io/M…
Browse files Browse the repository at this point in the history
  • Loading branch information
AzmiTouil committed Oct 21, 2024
1 parent ce21e8e commit bbf114a
Show file tree
Hide file tree
Showing 26 changed files with 964 additions and 191 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* This file is part of the Meeds project (https://meeds.io/).
*
* Copyright (C) 2020 - 2024 Meeds Lab contact@meedslab.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package io.meeds.wallet.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class RewardReportStatus {

private long sentDate;

private RewardPeriod period;

private long participantsCount;

private long recipientsCount;

private int achievementsCount;

private double tokensSent;

private double tokensToSend;

private boolean completelyProceeded;

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,30 @@
package io.meeds.wallet.reward.service;

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.List;
import java.util.Map;
import java.util.Set;

import io.meeds.wallet.model.*;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import org.exoplatform.social.core.identity.model.Identity;

import io.meeds.wallet.model.DistributionForecast;
import io.meeds.wallet.model.RewardPeriod;
import io.meeds.wallet.model.RewardPeriodType;
import io.meeds.wallet.model.RewardReport;
import io.meeds.wallet.model.RewardSettings;
import io.meeds.wallet.model.WalletReward;

/**
* A storage service to save/load reward settings
*/
public interface RewardReportService {

/**
* Gets rewards report switch {@link RewardPeriod}
*
* @param rewardPeriod a {@link RewardPeriod}
* @return a {@link RewardReportStatus}
*/
RewardReportStatus getReport(RewardPeriod rewardPeriod);

/**
* Compute rewards swicth configurations for the list of identities passed in
* parameters
Expand Down Expand Up @@ -88,6 +92,14 @@ public interface RewardReportService {
*/
RewardPeriod getRewardPeriod(RewardPeriodType periodType, LocalDate date);

/**
* Return the stored reward period by id
*
* @param rewardPeriodId reward period id
* @return {@link RewardPeriod}
*/
RewardPeriod getRewardPeriodById(long rewardPeriodId);

/**
* Retrieve a {@link RewardReport} corresponding to a period identified by its id
*
Expand Down Expand Up @@ -164,4 +176,28 @@ public interface RewardReportService {
*/
void replaceRewardTransactions(String oldHash, String newHash);

/**
* Gets wallet rewards by PeriodId and status
* first one
*
* @param periodId Reward Period id
* @param status Wallet reward status
* @param zoneId Wallet reward status
*/
Page<WalletReward> findWalletRewardsByPeriodIdAndStatus(long periodId, String status, ZoneId zoneId, Pageable pageable);


/**
* Set isChanged data map for periods not sent
*
* @param updatedSettings map of isChanged data for periods not sent
*
*/
void setRewardSettingChanged(Map<Long, Boolean> updatedSettings);

/**
* Gets isChanged data map for periods not sent
*
*/
Map<Long, Boolean> getRewardSettingChanged();
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import jakarta.transaction.Transactional;
import io.meeds.wallet.reward.entity.WalletRewardEntity;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
Expand All @@ -37,6 +38,14 @@ public interface RewardDAO extends JpaRepository<WalletRewardEntity, Long> {
""")
List<WalletRewardEntity> findRewardsByPeriodId(@Param("periodId") long periodId);

@Query("""
SELECT rw FROM Reward rw WHERE rw.period.id = :periodId AND
(:isValid = TRUE AND (rw.tokensSent > 0 OR rw.tokensToSend > 0) OR :isValid = FALSE AND (rw.tokensSent <= 0 AND rw.tokensToSend <= 0))
""")
Page<WalletRewardEntity> findWalletRewardsByPeriodIdAndStatus(@Param("periodId") long periodId,
@Param("isValid") boolean isValid,
Pageable pageable);

List<WalletRewardEntity> findWalletRewardEntitiesByIdentityId(long identityId, Pageable pageable);

double countWalletRewardEntitiesByIdentityId(long identityId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* This file is part of the Meeds project (https://meeds.io/).
*
* Copyright (C) 2020 - 2024 Meeds Lab contact@meedslab.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package io.meeds.wallet.reward.listener;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import io.meeds.wallet.model.RewardPeriod;
import io.meeds.wallet.model.RewardSettings;
import io.meeds.wallet.reward.service.RewardReportService;
import io.meeds.wallet.reward.service.RewardSettingsService;
import io.meeds.wallet.reward.service.WalletRewardReportService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import org.exoplatform.services.listener.Event;
import org.exoplatform.services.listener.Listener;
import org.exoplatform.services.listener.ListenerService;

import io.meeds.common.ContainerTransactional;

import jakarta.annotation.PostConstruct;

import static io.meeds.gamification.utils.Utils.*;
import static io.meeds.wallet.reward.service.WalletRewardSettingsService.REWARD_SETTINGS_UPDATED;
import static io.meeds.wallet.utils.WalletUtils.MODIFY_ADDRESS_ASSOCIATED_EVENT;
import static io.meeds.wallet.utils.WalletUtils.NEW_ADDRESS_ASSOCIATED_EVENT;

/**
* A listener that is triggered to update estimated reward report for current
* period.
*/
@Component
public class RewardReportUpdateListener extends Listener<Object, Map<String, String>> {

private static final List<String> EVENT_NAMES = Arrays.asList(NEW_ADDRESS_ASSOCIATED_EVENT,
MODIFY_ADDRESS_ASSOCIATED_EVENT,
REWARD_SETTINGS_UPDATED,
POST_CREATE_ANNOUNCEMENT_EVENT,
POST_UPDATE_ANNOUNCEMENT_EVENT,
POST_CANCEL_ANNOUNCEMENT_EVENT,
POST_REALIZATION_CREATE_EVENT,
POST_REALIZATION_UPDATE_EVENT,
POST_REALIZATION_CANCEL_EVENT);

@Autowired
private RewardReportService rewardReportService;

@Autowired
private RewardSettingsService rewardSettingsService;

@Autowired
private ListenerService listenerService;

@PostConstruct
public void init() {
EVENT_NAMES.forEach(name -> listenerService.addListener(name, this));
}

@ContainerTransactional
@Override
public void onEvent(Event<Object, Map<String, String>> event) {
String eventName = event.getEventName();
Map<Long, Boolean> updatedSettings = rewardReportService.getRewardSettingChanged();
if (REWARD_SETTINGS_UPDATED.equals(eventName)) {
List<RewardPeriod> rewardPeriods = rewardReportService.getRewardPeriodsNotSent();
updatedSettings = rewardPeriods.stream().collect(Collectors.toMap(RewardPeriod::getId, rewardPeriod -> true));
} else {
RewardSettings rewardSettings = rewardSettingsService.getSettings();
RewardPeriod rewardPeriod = rewardReportService.getRewardPeriod(rewardSettings.getPeriodType(), LocalDate.now());
updatedSettings.put(rewardPeriod.getId(), true);
}
rewardReportService.setRewardSettingChanged(updatedSettings);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,15 @@
import org.exoplatform.commons.api.notification.model.*;
import org.exoplatform.commons.api.notification.service.template.TemplateContext;
import org.exoplatform.commons.notification.template.TemplateUtils;
import org.exoplatform.container.ExoContainer;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.social.notification.plugin.SocialNotificationUtils;
import org.exoplatform.webui.utils.TimeConvertUtils;

public class RewardSuccessTemplateBuilder extends AbstractTemplateBuilder {

private static final Log LOG = ExoLogger.getLogger(RewardSuccessTemplateBuilder.class);

private ChannelKey channelKey;

private boolean pushNotification;

private ExoContainer container;

private RewardSettingsService rewardSettingsService;

public RewardSuccessTemplateBuilder(RewardSettingsService rewardSettingsService, ChannelKey channelKey) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.bind.DefaultValue;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PagedResourcesAssembler;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.PagedModel;
Expand All @@ -75,32 +77,23 @@ public class RewardReportREST {
@GetMapping(path = "compute")
@Secured("rewarding")
@Operation(
summary = "Compute rewards of wallets per a chosen period of time",
summary = "Gets rewards report per a chosen period of time",
method = "GET",
description = "returns a set of wallet reward object")
description = "returns a list of reward report")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Request fulfilled"),
@ApiResponse(responseCode = "400", description = "Invalid query input"),
@ApiResponse(responseCode = "401", description = "Unauthorized operation"),
@ApiResponse(responseCode = "500", description = "Internal server error") })
public List<RewardReport> computeRewards(@Parameter(description = "Page")
@RequestParam(value = "page", defaultValue = "0", required = false)
int page,
@Parameter(description = "Page size")
@RequestParam(value = "size", defaultValue = "12", required = false)
int size) {
public List<RewardReportStatus> getReportsStatus(@Parameter(description = "Page")
@RequestParam(value = "page", defaultValue = "0", required = false)
int page,
@Parameter(description = "Page size")
@RequestParam(value = "size", defaultValue = "12", required = false)
int size) {
int skip = page * size;
List<RewardPeriod> periods = generatePreviousPeriods(skip + size).subList(skip, skip + size);
List<RewardReport> rewardReports = periods.parallelStream()
.map(period -> {
RewardReport rewardReport =
rewardReportService.computeRewards(period.getPeriodMedianDate());
rewardReport.setPeriod(new RewardPeriodWithFullDate(rewardReport.getPeriod()));
return rewardReport;
})
.toList();
rewardReports.forEach(rewardReport -> rewardReport.setPeriod(new RewardPeriodWithFullDate(rewardReport.getPeriod())));
return rewardReports;
return periods.parallelStream().map(period -> rewardReportService.getReport(period)).toList();
}

@PostMapping(path = "period/compute")
Expand All @@ -121,6 +114,39 @@ public RewardReport computeRewardsByPeriod(@RequestBody
return rewardReport;
}

@GetMapping(path = "rewards")
@Secured("rewarding")
@Operation(summary = "Gets rewards of wallets per a chosen period of time", method = "GET", description = "returns the list of wallets per a chosen period of time")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Request fulfilled"),
@ApiResponse(responseCode = "400", description = "Invalid query input"),
@ApiResponse(responseCode = "401", description = "Unauthorized operation"),
@ApiResponse(responseCode = "500", description = "Internal server error") })
public PagedModel<EntityModel<WalletReward>> getWalletRewards(Pageable pageable,
PagedResourcesAssembler<WalletReward> assembler,
@Parameter(description = "Period id", required = true)
@RequestParam("periodId")
long periodId,
@Parameter(description = "Wallet reward status filtering, possible values: VALId and INVALID. Default value = VALId.")
@RequestParam(value = "status", defaultValue = "VALID")
String status,
@Parameter(description = "Field to sort by. Possible values: 'tokensSent', 'points'. Default is 'tokensSent'.")
@RequestParam(value = "sortField", defaultValue = "tokensSent") String sortField,
@Parameter(description = "Sort direction for tokensToSend field. Possible values: 'asc' (ascending) or 'desc' (descending). Default value = asc.")
@RequestParam(value = "sortDir", defaultValue = "asc") String sortDir) {

Sort sort = sortDir.equalsIgnoreCase("desc") ? Sort.by(sortField).descending() : Sort.by(sortField).ascending();

Pageable sortedPageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), sort);

Page<WalletReward> walletRewards;
walletRewards = rewardReportService.findWalletRewardsByPeriodIdAndStatus(periodId,
status,
rewardSettingsService.getSettings().zoneId(),
sortedPageable);
return assembler.toModel(walletRewards);
}

@PostMapping(path = "forecast")
@Secured("rewarding")
@Operation(
Expand Down Expand Up @@ -268,8 +294,8 @@ private List<RewardPeriod> generatePreviousPeriods(int count) {
ZonedDateTime currentDateTime = ZonedDateTime.now(zoneId);

return IntStream.range(0, count).mapToObj(i -> {
ZonedDateTime start;
ZonedDateTime end;
ZonedDateTime start = null;
ZonedDateTime end = null;

switch (periodType) {
case WEEK -> {
Expand All @@ -287,16 +313,14 @@ private List<RewardPeriod> generatePreviousPeriods(int count) {
.truncatedTo(ChronoUnit.DAYS);
end = start.plusMonths(3);
}
default -> throw new UnsupportedOperationException("Unknown period type");
}

RewardPeriod rewardPeriod = new RewardPeriod();
rewardPeriod.setRewardPeriodType(periodType);
rewardPeriod.setStartDateInSeconds(timeToSecondsAtDayStart(LocalDate.from(start), currentDateTime.getZone()));
rewardPeriod.setEndDateInSeconds(timeToSecondsAtDayStart(LocalDate.from(end), currentDateTime.getZone()));

return rewardPeriod;
}).collect(Collectors.toList());
}).toList();
}

}
Loading

0 comments on commit bbf114a

Please sign in to comment.