Skip to content

Commit

Permalink
FRI-635 Updated logic when canceling the build and added notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
QuyenLy87 committed May 31, 2023
1 parent 3ce2aca commit 00b7fcd
Show file tree
Hide file tree
Showing 21 changed files with 789 additions and 9 deletions.
31 changes: 30 additions & 1 deletion src/main/java/org/ihtsdo/buildcloud/core/dao/BuildDAOImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,36 @@ public void loadQaTestConfig(final Build build) throws IOException {

@Override
public void updateStatus(final Build build, final Build.Status newStatus) {
final Build.Status origStatus = build.getStatus();
String buildStatusPath = pathHelper.getStatusFilePath(build, build.getStatus());
Build.Status origStatus = build.getStatus();
if (origStatus != null) {
boolean isLatestStatus = false;
try {
S3Object s3Object = s3Client.getObject(buildBucketName, buildStatusPath);
if (s3Object != null) {
isLatestStatus = true;
}
} catch (AmazonS3Exception e) {
if (404 != e.getStatusCode()) {
throw e;
}
}
if (!isLatestStatus) {
Build lastBuild = find(build.getReleaseCenterKey(), build.getProductKey(), build.getId(), null, null, null, null);
origStatus = lastBuild.getStatus();
}
if (Build.Status.CANCEL_REQUESTED == origStatus
|| Build.Status.FAILED_INPUT_GATHER_REPORT_VALIDATION == origStatus
|| Build.Status.FAILED_INPUT_PREPARE_REPORT_VALIDATION == origStatus
|| Build.Status.FAILED_PRE_CONDITIONS == origStatus
|| Build.Status.FAILED_POST_CONDITIONS == origStatus
|| Build.Status.CANCELLED == origStatus
|| Build.Status.FAILED == origStatus
) {
throw new IllegalStateException("Could not update build status as it has been already " + origStatus.name());
}
}

build.setStatus(newStatus);
final String newStatusFilePath = pathHelper.getStatusFilePath(build, build.getStatus());
// Put new status before deleting old to avoid there being none.
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/org/ihtsdo/buildcloud/core/dao/NotificationDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.ihtsdo.buildcloud.core.dao;

import org.ihtsdo.buildcloud.core.entity.BuildStatusTracker;
import org.ihtsdo.buildcloud.core.entity.Notification;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;

import java.util.List;

public interface NotificationDao extends EntityDAO<Notification> {

Page<Notification> findAll(String recipient, PageRequest pageRequest);

Long countUnreadNotifications(String recipient);

List<Notification> findByRecipient(String recipient);

List<Notification> findByIds(List<Long> notificationIds);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.ihtsdo.buildcloud.core.dao;

import org.hibernate.query.Query;
import org.ihtsdo.buildcloud.core.entity.Notification;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class NotificationDaoImpl extends EntityDAOImpl<Notification> implements NotificationDao {

protected NotificationDaoImpl() {
super(Notification.class);
}

@Override
public Page<Notification> findAll(String recipient, PageRequest pageRequest) {
Query query = getCurrentSession().createQuery(
"select notification " +
"from Notification notification " +
"where notification.recipient = :recipient " +
"order by notification.createdDate DESC");
query.setParameter("recipient", recipient);
query.setFirstResult(pageRequest.getPageNumber() * pageRequest.getPageSize());
query.setMaxResults(pageRequest.getPageSize());

Query queryTotal = getCurrentSession().createQuery(
"select count(notification.id) " +
"from Notification notification " +
"where notification.recipient = :recipient");
queryTotal.setParameter("recipient", recipient);


return new PageImpl(query.list(), pageRequest, (long) queryTotal.uniqueResult());
}

@Override
public Long countUnreadNotifications(String recipient) {
Query queryTotal = getCurrentSession().createQuery(
"select count(notification.id) " +
"from Notification notification " +
"where notification.recipient = :recipient and notification.read = 'N'");
queryTotal.setParameter("recipient", recipient);

return (long) queryTotal.uniqueResult();
}

@Override
public List<Notification> findByRecipient(String recipient) {
Query query = getCurrentSession().createQuery(
"select notification " +
"from Notification notification " +
"where notification.recipient = :recipient");
query.setParameter("recipient", recipient);

return query.list();
}

@Override
public List<Notification> findByIds(List<Long> notificationIds) {
Query query = getCurrentSession().createQuery(
"select notification " +
"from Notification notification " +
"where notification.id in (:notificationIds)");
query.setParameter("notificationIds", notificationIds);

return query.list();
}
}
90 changes: 90 additions & 0 deletions src/main/java/org/ihtsdo/buildcloud/core/entity/Notification.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package org.ihtsdo.buildcloud.core.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;
import org.hibernate.annotations.Type;

import javax.persistence.*;

import java.util.Date;

@Entity
@Table(name = "notification")
public class Notification {

public enum NotificationType {
BUILD_RUN_OUT_OF_TIME
}

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;

@Column(name = "details")
private String details;

@Column(name = "recipient")
private String recipient;

@Column(name = "notification_type")
private String notificationType;

@Column(name = "created_date")
private Date createdDate;

@Type(type="yes_no")
@Column(name = "is_read")
private Boolean read;

public Notification() {
this.createdDate = new Date();
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getDetails() {
return details;
}

public void setDetails(String details) {
this.details = details;
}

public String getRecipient() {
return recipient;
}

public void setRecipient(String recipient) {
this.recipient = recipient;
}

public String getNotificationType() {
return notificationType;
}

public void setNotificationType(String notificationType) {
this.notificationType = notificationType;
}

public Date getCreatedDate() {
return createdDate;
}

public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}

public boolean isRead() {
return read;
}

public void setRead(boolean read) {
this.read = read;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -344,19 +344,24 @@ private String getBuildPackageName(String releaseCenter, String productKey) thro

@Override
public Build triggerBuild(Build build, Boolean enableTelemetryStream) {
if (dao.isBuildCancelRequested(build)) return build;

// Start the build telemetry stream. All future logging on this thread and it's children will be captured.
try {
if (Boolean.TRUE.equals(enableTelemetryStream)) {
TelemetryStream.start(LOGGER, dao.getTelemetryBuildLogFilePath(build));
}
// Get build configurations from S3
getBuildConfigurations(build);
if (dao.isBuildCancelRequested(build)) return build;

performPreconditionTesting(build);
// Stop processing when the pre_condition checks have failed
if (Status.FAILED_PRE_CONDITIONS == build.getStatus()) {
return build;
}
if (dao.isBuildCancelRequested(build)) return build;

boolean isAbandoned = checkSourceFile(build);
// execute build
if (!isAbandoned) {
Expand Down Expand Up @@ -1323,8 +1328,11 @@ public InputStream getBuildInputFilesPrepareReport(String releaseCenterKey, Stri
@Override
public void requestCancelBuild(String releaseCenterKey, String productKey, String buildId) throws ResourceNotFoundException, BadConfigurationException {
final Build build = getBuildOrThrow(releaseCenterKey, productKey, buildId);
//Only cancel build if the status is "BUILDING"
dao.assertStatus(build, Status.BUILDING);
//Only cancel build if the status is "QUEUED" or "BEFORE_TRIGGER" or "BUILDING"
if (Status.BUILDING != build.getStatus() && Status.QUEUED != build.getStatus() && Status.BEFORE_TRIGGER != build.getStatus() ) {
throw new BadConfigurationException("Build " + build.getCreationTime() + " is at status: " + build.getStatus().name()
+ " and is expected to be at status:" + Status.QUEUED.name() + " or " + Status.BEFORE_TRIGGER.name() + " or " + Status.BUILDING.name());
}
dao.updateStatus(build, Status.CANCEL_REQUESTED);
LOGGER.warn("Status of build {} has been updated to {}", build, Status.CANCEL_REQUESTED.name());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.ihtsdo.buildcloud.core.service;

import org.ihtsdo.buildcloud.core.entity.Notification;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;

import java.util.List;

public interface NotificationService {

Notification create(Notification notification);

Page<Notification> findAll(String username, PageRequest pageRequest);

Long countUnreadNotifications(String username);

List<Long> removeNotifications(List<Long> notificationIds);

List<Long> markNotificationsAsRead(List<Long> notificationIds);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package org.ihtsdo.buildcloud.core.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.ihtsdo.buildcloud.core.dao.NotificationDao;
import org.ihtsdo.buildcloud.core.entity.Notification;
import org.ihtsdo.sso.integration.SecurityUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@ConditionalOnProperty(name = "srs.manager", havingValue = "true")
@Service
@Transactional
public class NotificationServiceImpl implements NotificationService {

private Logger logger = LoggerFactory.getLogger(getClass());

@Autowired
private NotificationDao dao;

@Autowired
private SimpMessagingTemplate simpMessagingTemplate;

@Autowired
private ObjectMapper objectMapper;

@Override
public Notification create(Notification notification) {
dao.save(notification);
return notification;
}

@Override
public Page<Notification> findAll(String recipient, PageRequest pageRequest) {
return dao.findAll(recipient, pageRequest);
}

@Override
public Long countUnreadNotifications(String username) {
return dao.countUnreadNotifications(username);
}

@Override
public List<Long> removeNotifications(List<Long> notificationIds) {
String currentUser = SecurityUtil.getUsername();
List<Notification> notifications;
if (notificationIds == null || notificationIds.isEmpty()) {
notifications = dao.findByRecipient(currentUser);
} else {
notifications = dao.findByIds(notificationIds);
}
List<Long> removedNotificationIds = new ArrayList<>();
for (Notification notification : notifications) {
removedNotificationIds.add(notification.getId());
dao.delete(notification);
}

try {
Map<String, Object> message = new HashMap<>();
message.put("event", "DELETE_NOTIFICATIONS");
simpMessagingTemplate.convertAndSend("/topic/user/" + currentUser + "/notification", objectMapper.writeValueAsString(message));
} catch (JsonProcessingException e) {
logger.error("Failed to send message through web-socket", e);
}
return removedNotificationIds;
}

@Override
public List<Long> markNotificationsAsRead(List<Long> notificationIds) {
String currentUser = SecurityUtil.getUsername();
List<Notification> notifications = dao.findByIds(notificationIds);
List<Long> readNotifications = new ArrayList<>();
for (Notification notification : notifications) {
notification.setRead(Boolean.TRUE);
readNotifications.add(notification.getId());
dao.update(notification);
}
try {
Map<String, Object> message = new HashMap<>();
message.put("event", "MARK_NOTIFICATIONS_AS_READ");
simpMessagingTemplate.convertAndSend("/topic/user/" + currentUser + "/notification", objectMapper.writeValueAsString(message));
} catch (JsonProcessingException e) {
logger.error("Failed to send message through web-socket", e);
}
return readNotifications;
}
}
Loading

0 comments on commit 00b7fcd

Please sign in to comment.