Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
package org.gridsuite.useradmin.server.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
Expand All @@ -16,13 +15,15 @@
import org.gridsuite.useradmin.server.dto.UserConnection;
import org.gridsuite.useradmin.server.dto.UserInfos;
import org.gridsuite.useradmin.server.dto.UserProfile;
import org.gridsuite.useradmin.server.repository.AnnouncementEntity;
import org.gridsuite.useradmin.server.service.UserAdminService;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.UUID;

/**
* @author Etienne Homer <etienne.homer at rte-france.com>
Expand Down Expand Up @@ -146,27 +147,38 @@ public ResponseEntity<List<UserConnection>> getConnections(@RequestHeader("userI
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(service.getConnections(userId));
}

@PostMapping(value = "/messages/maintenance")
@Operation(summary = "send a message to all users connected")
@PostMapping(value = "/announcements")
@Operation(summary = "Send an announcement to all the connected users")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "message sent"),
@ApiResponse(responseCode = "200", description = "announcement sent"),
@ApiResponse(responseCode = "403", description = "user is not an admin")
})
public ResponseEntity<Void> sendMaintenanceMessage(@RequestHeader("userId") String userId,
@Parameter(description = "the display time of the message in seconds") @RequestParam(value = "durationInSeconds", required = false) Integer duration,
@Parameter(description = "the message to display") @RequestBody String message) {
service.sendMaintenanceMessage(userId, duration, message);
public ResponseEntity<Void> sendAnnouncement(@RequestHeader("userId") String userId,
@RequestBody AnnouncementEntity announcement) {
service.sendAnnouncement(announcement, userId);
return ResponseEntity.ok().build();
}

@PostMapping(value = "/messages/cancel-maintenance")
@Operation(summary = "send a message to all users connected")
@DeleteMapping(value = "/announcements/{announcementId}")
@Operation(summary = "Cancel and delete an announcement")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "message sent"),
@ApiResponse(responseCode = "403", description = "user is not an admin")
@ApiResponse(responseCode = "200", description = "announcement canceled"),
@ApiResponse(responseCode = "403", description = "user is not an admin"),
@ApiResponse(responseCode = "404", description = "announcement not found")
})
public ResponseEntity<Void> sendCancelMaintenanceMessage(@RequestHeader("userId") String userId) {
service.sendCancelMaintenanceMessage(userId);
public ResponseEntity<Void> cancelAnnouncement(@RequestHeader("userId") String userId,
@PathVariable("announcementId") UUID announcementId) {
service.cancelAnnouncement(announcementId, userId);
return ResponseEntity.ok().build();
}

@GetMapping(value = "/announcements")
@Operation(summary = "Get all the announcements")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "announcements retrieved"),
@ApiResponse(responseCode = "403", description = "user is not an admin")
})
public ResponseEntity<List<AnnouncementEntity>> getAllAnnouncements(@RequestHeader("userId") String userId) {
return ResponseEntity.ok(service.getAllAnnouncements(userId));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* Copyright (c) 2024, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

package org.gridsuite.useradmin.server.repository;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.time.Duration;
import java.time.Instant;
import java.util.UUID;

/**
* @author Florent MILLOT <florent.millot at rte-france.com>
*/
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Entity
@Table(name = "announcement")
public class AnnouncementEntity {

public AnnouncementEntity(String message, Duration duration) {
this.message = message;
this.duration = duration;
}

@Id
@GeneratedValue
@Column
private UUID id;

@Column(nullable = false)
private Instant creationDate = Instant.now();

@Column(nullable = false)
private String message;

@Column
private Duration duration;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright (c) 2024, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

package org.gridsuite.useradmin.server.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.UUID;

/**
* @author Florent MILLOT <florent.millot at rte-france.com>
*/
@Repository
public interface AnnouncementRepository extends JpaRepository<AnnouncementEntity, UUID> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Copyright (c) 2024, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

package org.gridsuite.useradmin.server.service;

import org.gridsuite.useradmin.server.repository.AnnouncementEntity;
import org.gridsuite.useradmin.server.repository.AnnouncementRepository;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;

import java.util.List;
import java.util.Objects;
import java.util.UUID;

/**
* @author Florent MILLOT <florent.millot at rte-france.com>
*/
@Service
public class AnnouncementService {

private final AnnouncementRepository announcementRepository;
private final NotificationService notificationService;

public AnnouncementService(final AnnouncementRepository announcementRepository,
final NotificationService notificationService) {
this.announcementRepository = Objects.requireNonNull(announcementRepository);
this.notificationService = Objects.requireNonNull(notificationService);
}

@Transactional
public void sendAnnouncement(AnnouncementEntity announcement) {
this.announcementRepository.deleteAll(); // for now, only one message at a time
this.announcementRepository.save(announcement);
if (announcement.getDuration() == null) {
notificationService.emitMaintenanceMessage(announcement.getMessage());
} else {
notificationService.emitMaintenanceMessage(announcement.getMessage(), announcement.getDuration().toSeconds());
}
Comment on lines +40 to +44
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this can be handled in the EmitMessage method

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have done that also, but it's not a big deal and does not change that much so I kept the existing code

}

@Transactional
public void cancelAnnouncement(UUID announcementId) {
if (!announcementRepository.existsById(announcementId)) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Unable to find announcement");
}
this.announcementRepository.deleteById(announcementId);
notificationService.emitCancelMaintenanceMessage();
}

@Transactional(readOnly = true)
public List<AnnouncementEntity> getAllAnnouncements() {
return this.announcementRepository.findAll();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ private void sendMessage(Message<String> message) {
updatePublisher.send("publishMessage-out-0", message);
}

public void emitMaintenanceMessage(String message, int duration) {
public void emitMaintenanceMessage(String message, long duration) {
sendMessage(MessageBuilder.withPayload(message)
.setHeader(HEADER_MESSAGE_TYPE, MESSAGE_TYPE_MAINTENANCE)
.setHeader(HEADER_DURATION, duration)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.gridsuite.useradmin.server.dto.UserInfos;
import org.gridsuite.useradmin.server.dto.UserProfile;
import org.gridsuite.useradmin.server.entity.UserProfileEntity;
import org.gridsuite.useradmin.server.repository.AnnouncementEntity;
import org.gridsuite.useradmin.server.repository.UserInfosRepository;
import org.gridsuite.useradmin.server.entity.UserInfosEntity;
import org.gridsuite.useradmin.server.repository.UserProfileRepository;
Expand All @@ -20,12 +21,8 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.*;

import static org.gridsuite.useradmin.server.UserAdminException.Type.FORBIDDEN;
import static org.gridsuite.useradmin.server.UserAdminException.Type.NOT_FOUND;

/**
Expand All @@ -39,6 +36,7 @@ public class UserAdminService {
private final NotificationService notificationService;
private final AdminRightService adminRightService;
private final UserProfileService userProfileService;
private final AnnouncementService announcementService;
private final UserAdminService self;

private final UserAdminApplicationProps applicationProps;
Expand All @@ -50,6 +48,7 @@ public UserAdminService(final UserInfosRepository userInfosRepository,
final NotificationService notificationService,
final UserProfileService userProfileService,
final UserAdminApplicationProps applicationProps,
final AnnouncementService announcementService,
@Lazy final UserAdminService userAdminService) {
this.userInfosRepository = Objects.requireNonNull(userInfosRepository);
this.userProfileRepository = Objects.requireNonNull(userProfileRepository);
Expand All @@ -58,6 +57,7 @@ public UserAdminService(final UserInfosRepository userInfosRepository,
this.notificationService = Objects.requireNonNull(notificationService);
this.userProfileService = Objects.requireNonNull(userProfileService);
this.applicationProps = Objects.requireNonNull(applicationProps);
this.announcementService = Objects.requireNonNull(announcementService);
this.self = Objects.requireNonNull(userAdminService);
}

Expand Down Expand Up @@ -108,8 +108,8 @@ public void updateUser(String sub, String userId, UserInfos userInfos) {
public boolean subExists(String sub) {
final List<String> admins = adminRightService.getAdmins();
final boolean isAllowed = admins.isEmpty() && userInfosRepository.count() == 0L
|| admins.contains(sub)
|| userInfosRepository.existsBySub(sub);
|| admins.contains(sub)
|| userInfosRepository.existsBySub(sub);
connectionsService.recordConnectionAttempt(sub, isAllowed);
return isAllowed;
}
Expand Down Expand Up @@ -146,21 +146,18 @@ public boolean userIsAdmin(@NonNull String userId) {
return adminRightService.isAdmin(userId);
}

public void sendMaintenanceMessage(String userId, Integer durationInSeconds, String message) {
if (!adminRightService.isAdmin(userId)) {
throw new UserAdminException(FORBIDDEN);
}
if (durationInSeconds == null) {
notificationService.emitMaintenanceMessage(message);
} else {
notificationService.emitMaintenanceMessage(message, durationInSeconds);
}
public void sendAnnouncement(AnnouncementEntity announcement, String userId) {
adminRightService.assertIsAdmin(userId);
announcementService.sendAnnouncement(announcement);
}

public void sendCancelMaintenanceMessage(String userId) {
if (!adminRightService.isAdmin(userId)) {
throw new UserAdminException(FORBIDDEN);
}
notificationService.emitCancelMaintenanceMessage();
public void cancelAnnouncement(UUID announcementId, String userId) {
adminRightService.assertIsAdmin(userId);
announcementService.cancelAnnouncement(announcementId);
}

public List<AnnouncementEntity> getAllAnnouncements(String userId) {
adminRightService.assertIsAdmin(userId);
return announcementService.getAllAnnouncements();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet author="florent (generated)" id="1711719892005-1">
<createTable tableName="announcement">
<column name="id" type="UUID">
<constraints nullable="false" primaryKey="true" primaryKeyName="announcementPK"/>
</column>
<column name="creation_date" type="TIMESTAMP(6)">
<constraints nullable="false"/>
</column>
<column name="duration" type="numeric(21, 0)"/>
<column name="message" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
</databaseChangeLog>
4 changes: 4 additions & 0 deletions src/main/resources/db/changelog/db.changelog-master.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ databaseChangeLog:
- include:
file: changesets/changelog_20240715T114052Z.xml
relativeToChangelogFile: true
- include:
file: changesets/changelog_20240329T134444Z.xml
relativeToChangelogFile: true

Loading
Loading