ListDelegatedNewsResource.java
/*
* Copyright (C) 2000 - 2026 Silverpeas
*
* 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.
*
* As a special exception to the terms and conditions of version 3.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* Open Source Software ("FLOSS") applications as described in Silverpeas's
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* "https://www.silverpeas.org/legal/floss_exception.html"
*
* 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 <https://www.gnu.org/licenses/>.
*/
package org.silverpeas.components.delegatednews.web;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.silverpeas.components.delegatednews.DelegatedNewsRuntimeException;
import org.silverpeas.components.delegatednews.model.DelegatedNews;
import org.silverpeas.components.delegatednews.service.DelegatedNewsService;
import org.silverpeas.core.admin.user.model.SilverpeasRole;
import org.silverpeas.core.annotation.WebService;
import org.silverpeas.core.web.rs.RESTWebService;
import org.silverpeas.core.web.rs.annotation.Authorized;
import org.silverpeas.core.rs.doc.NotFound;
import jakarta.inject.Inject;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response.Status;
import java.util.ArrayList;
import java.util.List;
/**
* A REST Web resource representing a given delegated news. It is a web service that provides access
* to a delegated news referenced by its URL.
*/
@WebService
@Path(ListDelegatedNewsResource.PATH + "/{instanceId}")
@Authorized
public class ListDelegatedNewsResource extends RESTWebService {
static final String PATH = "delegatednews";
@Inject
private DelegatedNewsService delegatednewsService;
@PathParam("instanceId")
private String instanceId;
/**
* Gets a business service on delegatedNews.
*
* @return a delegatedNews service instance.
*/
protected DelegatedNewsService getDelegatedNewsService() {
return this.delegatednewsService;
}
@Override
protected String getResourceBasePath() {
return PATH;
}
@Override
public String getComponentId() {
return this.instanceId;
}
/**
* Updates order or delete the delegatedNews from the JSON representation. If the user isn't
* authenticated, a 401 HTTP code is returned. If the user isn't authorized to save the delegated
* news, a 403 is returned. If a problem occurs when processing the request, a 503 HTTP code is
* returned.
*
* <p>
* The delegated news are received as a list, not as a Java array: the JSON provider of the SCIM
* library, registered for the whole REST API, fails with any Java array.
* </p>
*
* @param newDelegatedNews the list of the delegated news to update order or to delete
* @return the new list of delegated news after update or delete
*/
@Operation(summary = "Reorders or deletes the delegated news.",
description = "The whole list of the delegated news to keep is expected, in the order they " +
"have to be displayed. The delegated news missing from that list are deleted.")
@ApiResponse(responseCode = "200", description = "The delegated news once reordered or deleted.",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = DelegatedNewsEntity.class))))
@NotFound
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public List<DelegatedNewsEntity> updateDelegatedNews(
final List<DelegatedNewsEntity> newDelegatedNews) {
checkIsManager();
List<DelegatedNewsEntity> updatedEntities;
List<DelegatedNews> initialListDelegatedNews = getDelegatedNewsService().getAllDelegatedNews();
try {
if (initialListDelegatedNews.size() == newDelegatedNews.size()) {// Update Order
updatedEntities = updateOrder(newDelegatedNews);
} else if (initialListDelegatedNews.size() > newDelegatedNews.size()) {// Delete
deleteList(newDelegatedNews, initialListDelegatedNews);
updatedEntities = newDelegatedNews;
} else {
updatedEntities = List.of();
}
} catch (DelegatedNewsRuntimeException ex) {
throw new WebApplicationException(ex, Status.NOT_FOUND);
} catch (Exception ex) {
throw new WebApplicationException(ex, Status.SERVICE_UNAVAILABLE);
}
return updatedEntities;
}
/**
* Checks the user manages the delegated news, their modification and their deletion being
* reserved to the managers of this application. The authorization performed by the REST
* framework only validates the access to the component instance, whatever the role played in it,
* so it isn't enough here.
*/
void checkIsManager() {
final SilverpeasRole role = getHighestUserRole();
if (role == null || !role.isGreaterThanOrEquals(SilverpeasRole.ADMIN)) {
throw new WebApplicationException(Status.FORBIDDEN);
}
}
private void deleteList(final List<DelegatedNewsEntity> newDelegatedNews,
List<DelegatedNews> initialListDelegatedNews) {
boolean found;
for (DelegatedNews delegatedNews : initialListDelegatedNews) {
String pubId = delegatedNews.getPubId();
found = false;
for (DelegatedNewsEntity delegatedNewsEntity : newDelegatedNews) {
// the new tab of DelegatedNewsEntity without the delegated news deleted
if (pubId.equals(delegatedNewsEntity.getPubId())) {
found = true;
break;
}
}
if (!found) {
getDelegatedNewsService().deleteDelegatedNews(pubId); // delete the delegatedNews
}
}
}
private List<DelegatedNewsEntity> updateOrder(final List<DelegatedNewsEntity> newDelegatedNews) {
List<DelegatedNewsEntity> results = new ArrayList<>(newDelegatedNews.size());
int order = 0;
for (DelegatedNewsEntity delegatedNewsEntity : newDelegatedNews) {
// the tab of DelegatedNewsEntity is in the new order
DelegatedNews delegatedNews = delegatedNewsEntity.toDelegatedNews();
DelegatedNews delegatedNewsUpdated =
getDelegatedNewsService().updateOrderDelegatedNews(delegatedNews.getPubId(), order);
results.add(DelegatedNewsEntity.fromDelegatedNews(delegatedNewsUpdated));
order++;
}
return results;
}
}