/*
* Copyright (C) 2008-2020, Juick
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
package com.juick.www.api;
import com.juick.model.*;
import com.juick.service.*;
import com.juick.util.HttpForbiddenException;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import jakarta.inject.Inject;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
/**
* Created by vitalyster on 24.10.2016.
*/
@RestController
public class Notifications {
private static final Logger logger = LoggerFactory.getLogger("www");
@Inject
private MessagesService messagesService;
@Inject
private SubscriptionService subscriptionService;
@Inject
private UserService userService;
@Inject
private TelegramService telegramService;
@Inject
private User serviceUser;
private User collectTokens(Integer uid) {
User user = userService.getUserByUID(uid).orElse(AnonymousUser.INSTANCE);
user.setUnreadCount(messagesService.getUnread(user).size());
var tokens = userService.getTokens(List.of(user.getUid()));
var xmppJids = userService.getJIDsbyUID(uid).stream()
.map(jid -> new ExternalToken(null, "xmpp", jid, null));
var tgIds = telegramService.getTelegramIdentifiers(Collections.singletonList(user)).stream()
.map(tgId -> new ExternalToken(null, "durov", String.valueOf(tgId), null));
user.setTokens(Stream.concat(Stream.concat(tokens.stream(), xmppJids), tgIds).toList());
return user;
}
@Hidden
@RequestMapping(value = "/api/notifications", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List doGet(
@Parameter(hidden = true) User visitor,
@RequestParam(required = false, defaultValue = "0") int uid,
@RequestParam(required = false, defaultValue = "0") int mid,
@RequestParam(required = false, defaultValue = "0") int rid) {
if (!(visitor.equals(serviceUser))) {
throw new HttpForbiddenException();
}
if (uid > 0 && mid == 0) {
// PM
return Collections.singletonList(collectTokens(uid));
} else {
if (mid > 0) {
// reply
Message msg = messagesService.getMessage(mid).orElseThrow(IllegalStateException::new);
List users = Collections.emptyList();
if (rid > 0) {
Message op = messagesService.getMessage(mid).orElseThrow(IllegalStateException::new);
Message reply = messagesService.getReply(mid, rid);
if (reply != null) {
users = subscriptionService.getUsersSubscribedToComments(op, reply);
} else {
logger.warn("Reply not found: {}/{}", mid, rid);
}
} else {
users = subscriptionService.getSubscribedUsers(msg.getUser().getUid(), msg);
}
return users.stream().map(User::getUid)
.map(this::collectTokens).toList();
} else {
// read
return Collections.singletonList(collectTokens(uid));
}
}
}
@Hidden
@RequestMapping(value = "/api/notifications", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE)
public Status doDelete(
@Parameter(hidden = true) User visitor,
@RequestBody List list) {
if (!visitor.equals(serviceUser)) {
throw new HttpForbiddenException();
}
list.forEach(t -> {
userService.deleteToken(t.type(), t.token());
});
return Status.OK;
}
@Hidden
@RequestMapping(value = "/api/notifications/delete", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public Status doDeleteTokens(
@Parameter(hidden = true) User visitor,
@RequestBody List list) {
if (!visitor.equals(serviceUser)) {
throw new HttpForbiddenException();
}
list.forEach(t -> userService.deleteToken(t.type(), t.token()));
return Status.OK;
}
@Hidden
@RequestMapping(value = "/api/notifications", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE)
public Status doPut(
@Parameter(hidden = true) User visitor,
@RequestBody List list) {
var userTokens = collectTokens(visitor.getUid());
list.forEach(t -> {
logger.debug("Received new token from {}: type {} token {}", visitor.getName(), t.type(), t.token());
if (userTokens.getTokens().stream().noneMatch(existing -> existing.token().equals(t.token()))) {
var added = userService.addToken(visitor.getUid(), t.type(), t.token());
logger.debug("Token added: {}", added);
}
});
return Status.OK;
}
@Deprecated
@RequestMapping(value = "/api/android/register", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public Status doAndroidRegister(
@Parameter(hidden = true) User visitor,
@RequestParam(name = "regid") String regId) {
var userTokens = collectTokens(visitor.getUid());
if (userTokens.getTokens().stream().noneMatch(existing -> existing.token().equals(regId))) {
userService.addToken(visitor.getUid(), "fcm", regId);
}
return Status.OK;
}
@Deprecated
@RequestMapping(value = "/api/winphone/register", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public Status doWinphoneRegister(
@Parameter(hidden = true) User visitor,
@RequestParam(name = "url") String regId) {
var userTokens = collectTokens(visitor.getUid());
if (userTokens.getTokens().stream().noneMatch(existing -> existing.token().equals(regId))) {
userService.addToken(visitor.getUid(), "mpns", regId);
}
return Status.OK;
}
}