package io.kaif.web.v1; import static java.util.stream.Collectors.*; import java.util.Date; import java.util.List; import javax.validation.Valid; import javax.validation.constraints.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import io.swagger.annotations.Api; import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiOperation; import io.kaif.flake.FlakeId; import io.kaif.model.clientapp.ClientAppScope; import io.kaif.model.clientapp.ClientAppUserAccessToken; import io.kaif.model.debate.Debate; import io.kaif.model.feed.FeedAsset; import io.kaif.service.ArticleService; import io.kaif.service.FeedService; import io.kaif.web.v1.dto.V1AssetType; import io.kaif.web.v1.dto.V1DebateDto; import io.kaif.web.v1.dto.V1FeedAssetDto; @Api(tags = "feed", description = "Personal news feed") @RestController @RequestMapping(value = "/v1/feed", produces = MediaType.APPLICATION_JSON_VALUE) public class V1FeedResource { static class AcknowledgeEntry { @ApiModelProperty(required = true) @NotNull public FlakeId assetId; } @Autowired private ArticleService articleService; @Autowired private FeedService feedService; @ApiOperation(value = "[feed] Latest news", notes = "List latest FeedAssets, 25 assets a page. " + "To retrieve next page, passing last asset id of previous page in parameter start-asset-id.") @RequiredScope(ClientAppScope.FEED) @RequestMapping(value = "/news", method = RequestMethod.GET) public List<V1FeedAssetDto> news(ClientAppUserAccessToken token, @RequestParam(value = "start-asset-id", required = false) FlakeId startAssetId) { List<FeedAsset> feedAssets = feedService.listFeeds(token, startAssetId); List<Debate> debates = articleService.listDebatesByIdWithCache(feedAssets.stream() .map(FeedAsset::getAssetId) .collect(toList())); // currently only support debate from reply return feedAssets.stream() .filter(asset -> asset.getAssetType() == FeedAsset.AssetType.DEBATE_FROM_REPLY) .map(asset -> { V1DebateDto found = debates.stream() .filter(debate -> debate.getDebateId().equals(asset.getAssetId())) .map(Debate::toV1Dto) .findAny() .orElse(null); return new V1FeedAssetDto(asset.getAssetId().toString(), V1AssetType.DEBATE_FROM_REPLY, Date.from(asset.getCreateTime()), asset.isAcked(), found); }) .collect(toList()); } @ApiOperation(value = "[feed] Get unread count in news feed", notes = "Get unread count in news feed, max value is 11 regardless real unread count. " + "The method should not repeat invoke in short time, we recommend once per 5 minutes.") @RequiredScope(ClientAppScope.FEED) @RequestMapping(value = "/news-unread-count", method = RequestMethod.GET) public int newsUnreadCount(ClientAppUserAccessToken token) { return feedService.countUnread(token); } @ApiOperation(value = "[feed] Acknowledge a FeedAsset", notes = "A FeedAsset set to acknowledged will treat all assets before it as read. " + "Typically you should acknowledge the latest feedAssetId you received " + "when the user open news feed window in your app.") @RequiredScope(ClientAppScope.FEED) @RequestMapping(value = "/acknowledge", method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_VALUE }) public void acknowledge(ClientAppUserAccessToken token, @Valid @RequestBody AcknowledgeEntry entry) { feedService.acknowledge(token, entry.assetId); } }