diff --git a/modules/research-framework/research-service/pom.xml b/modules/research-framework/research-service/pom.xml
index 79deaf1ee8..ccd45abe81 100644
--- a/modules/research-framework/research-service/pom.xml
+++ b/modules/research-framework/research-service/pom.xml
@@ -17,233 +17,247 @@ specific language governing permissions and limitations
under the License.
-->
- 4.0.0
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
-
- org.apache.airavata
- airavata
- 0.21-SNAPSHOT
- ../../../pom.xml
-
+
+ org.apache.airavata
+ airavata
+ 0.21-SNAPSHOT
+ ../../../pom.xml
+
- research-service
- Airavata Research Service
+ research-service
+ Airavata Research Service
-
- apache-airavata-research-service-${project.version}
-
+
+ apache-airavata-research-service-${project.version}
+
-
-
- org.mariadb.jdbc
- mariadb-java-client
-
-
- ch.qos.logback
- logback-classic
-
-
- ch.qos.logback
- logback-core
-
-
-
-
- org.springframework.boot
- spring-boot-starter-web
-
-
- org.apache.logging.log4j
- log4j-to-slf4j
-
-
- ch.qos.logback
- logback-classic
-
-
- ch.qos.logback
- logback-core
-
-
-
-
- org.springframework.boot
- spring-boot-starter-data-jpa
-
-
- org.apache.logging.log4j
- log4j-to-slf4j
-
-
- ch.qos.logback
- logback-classic
-
-
- ch.qos.logback
- logback-core
-
-
-
-
- org.springframework.boot
- spring-boot-starter-log4j2
-
-
- org.springdoc
- springdoc-openapi-starter-webmvc-ui
-
-
- io.grpc
- grpc-stub
-
-
- ch.qos.logback
- logback-classic
-
-
- ch.qos.logback
- logback-core
-
-
-
-
- io.grpc
- grpc-protobuf
-
-
- ch.qos.logback
- logback-classic
-
-
- ch.qos.logback
- logback-core
-
-
-
-
- com.google.protobuf
- protobuf-java
-
-
- ch.qos.logback
- logback-classic
-
-
- ch.qos.logback
- logback-core
-
-
-
-
- net.devh
- grpc-server-spring-boot-starter
-
-
- ch.qos.logback
- logback-classic
-
-
- ch.qos.logback
- logback-core
-
-
-
-
- javax.validation
- validation-api
-
-
- org.apache.airavata
- airavata-api
- ${project.version}
-
-
- ch.qos.logback
- logback-classic
-
-
- ch.qos.logback
- logback-core
-
-
- org.slf4j
- slf4j-log4j12
-
-
-
-
+
+
+ org.mariadb.jdbc
+ mariadb-java-client
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ ch.qos.logback
+ logback-core
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.apache.logging.log4j
+ log4j-to-slf4j
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ ch.qos.logback
+ logback-core
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ org.apache.logging.log4j
+ log4j-to-slf4j
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ ch.qos.logback
+ logback-core
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-log4j2
+
+
+ org.springframework.boot
+ spring-boot-starter-mail
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ ch.qos.logback
+ logback-core
+
+
+
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+
+
+ io.grpc
+ grpc-stub
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ ch.qos.logback
+ logback-core
+
+
+
+
+ io.grpc
+ grpc-protobuf
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ ch.qos.logback
+ logback-core
+
+
+
+
+ com.google.protobuf
+ protobuf-java
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ ch.qos.logback
+ logback-core
+
+
+
+
+ net.devh
+ grpc-server-spring-boot-starter
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ ch.qos.logback
+ logback-core
+
+
+
+
+ javax.validation
+ validation-api
+
+
+ org.apache.airavata
+ airavata-api
+ ${project.version}
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ ch.qos.logback
+ logback-core
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+
+
-
-
-
- org.apache.maven.plugins
- maven-assembly-plugin
-
-
- research-service-distribution-package
- package
-
- single
-
-
- posix
- ${research.service.dist.name}
-
- src/main/assembly/research-service-bin-assembly.xml
-
- false
-
-
-
-
-
- io.github.ascopes
- protobuf-maven-plugin
-
- 4.30.1
-
- ${project.basedir}/src/main/proto
-
-
-
- io.grpc
- protoc-gen-grpc-java
- 1.73.0
- @generated=omit
-
-
-
-
-
-
- generate
-
- generate-sources
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
-
- 17
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
-
-
- src/main/resources/log4j2.xml
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ research-service-distribution-package
+ package
+
+ single
+
+
+ posix
+ ${research.service.dist.name}
+
+ src/main/assembly/research-service-bin-assembly.xml
+
+ false
+
+
+
+
+
+ io.github.ascopes
+ protobuf-maven-plugin
+
+ 4.30.1
+
+ ${project.basedir}/src/main/proto
+
+
+
+ io.grpc
+ protoc-gen-grpc-java
+ 1.73.0
+ @generated=omit
+
+
+
+
+
+
+ generate
+
+ generate-sources
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 17
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ src/main/resources/log4j2.xml
+
+
+
+
+
+
diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/AiravataService.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/AiravataService.java
index 8e81ad6b2f..7222de879b 100644
--- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/AiravataService.java
+++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/AiravataService.java
@@ -21,6 +21,7 @@
import org.apache.airavata.model.security.AuthzToken;
import org.apache.airavata.model.user.UserProfile;
+import org.apache.airavata.research.service.enums.EmailType;
import org.apache.airavata.research.service.model.UserContext;
import org.apache.airavata.service.profile.client.ProfileServiceClientFactory;
import org.apache.airavata.service.profile.user.cpi.UserProfileService;
@@ -28,6 +29,7 @@
import org.apache.thrift.TException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@@ -36,12 +38,15 @@ public class AiravataService {
private static final Logger LOGGER = LoggerFactory.getLogger(AiravataService.class);
- @Value("${airavata.user-profile.server.url:airavata.host}")
+ @Value("${airavata.user-profile.server.url:localhost}")
private String profileServerUrl;
@Value("${airavata.user-profile.server.port:8962}")
private int profileServerPort;
+ @Autowired
+ private EmailService emailService;
+
public UserProfileService.Client userProfileClient() {
try {
LOGGER.info("User profile client initialized");
@@ -63,6 +68,10 @@ public UserProfile getUserProfile(String userId) {
public UserProfile getUserProfile(AuthzToken authzToken, String userId, String gatewayId) {
try {
+ boolean result = userProfileClient().doesUserExist(authzToken, userId, gatewayId);
+ if (!result) {
+ sendEmail(userId);
+ }
return userProfileClient().getUserProfileById(authzToken, userId, gatewayId);
} catch (TException e) {
LOGGER.error("Error while getting user profile with the id: {} in the gateway: {}", userId, gatewayId, e);
@@ -70,4 +79,10 @@ public UserProfile getUserProfile(AuthzToken authzToken, String userId, String g
"Error while getting user profile with the id: " + userId + " in the gateway: " + gatewayId, e);
}
}
+
+ private void sendEmail(String to) {
+ if (!emailService.hasSentEmail(to, EmailType.NEW_USER)) {
+ emailService.sendSimpleMessage(to, EmailType.NEW_USER);
+ }
+ }
}
diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/EmailService.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/EmailService.java
new file mode 100644
index 0000000000..04750517c5
--- /dev/null
+++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/EmailService.java
@@ -0,0 +1,66 @@
+/**
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+package org.apache.airavata.research.service;
+
+import org.apache.airavata.research.service.enums.EmailType;
+import org.apache.airavata.research.service.model.entity.EmailRecord;
+import org.apache.airavata.research.service.model.repo.EmailRecordRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.mail.SimpleMailMessage;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.stereotype.Service;
+
+@Service
+public class EmailService {
+
+ @Autowired
+ private JavaMailSender mailSender;
+
+ @Value("${spring.mail.username}")
+ private String fromEmail;
+
+ @Value("${airavata.research-portal.admin-notification-email}")
+ private String adminEmail;
+
+ @Autowired
+ private EmailRecordRepository emailRecordRepository;
+
+ public void sendSimpleMessage(String newUserEmail, EmailType type) {
+ SimpleMailMessage message = new SimpleMailMessage();
+ message.setFrom(fromEmail);
+ message.setTo(adminEmail);
+ message.setSubject(type.getSubject());
+ message.setText(type.getMessage(newUserEmail));
+ mailSender.send(message);
+
+ EmailRecord record = new EmailRecord();
+ record.setEmailType(type);
+ record.setUserId(newUserEmail);
+ emailRecordRepository.save(record);
+ emailRecordRepository.flush();
+ }
+
+ public boolean hasSentEmail(String toEmail, EmailType emailType) {
+ return emailRecordRepository
+ .findByUserIdAndEmailType(toEmail, emailType)
+ .isPresent();
+ }
+}
diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/enums/EmailType.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/enums/EmailType.java
new file mode 100644
index 0000000000..77853f900a
--- /dev/null
+++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/enums/EmailType.java
@@ -0,0 +1,40 @@
+/**
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+package org.apache.airavata.research.service.enums;
+
+public enum EmailType {
+ NEW_USER {
+ public String getSubject() {
+ return "New Cybershuttle User";
+ }
+
+ public String getMessage(String newUserEmail) {
+ return String.format(
+ """
+ Hi, %s has just signed up for Cybershuttle.
+ """,
+ newUserEmail);
+ }
+ };
+
+ public abstract String getSubject();
+
+ public abstract String getMessage(String newUserEmail);
+}
diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/EmailRecord.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/EmailRecord.java
new file mode 100644
index 0000000000..8317b41b95
--- /dev/null
+++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/EmailRecord.java
@@ -0,0 +1,100 @@
+/**
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+package org.apache.airavata.research.service.model.entity;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EntityListeners;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.Id;
+import java.time.Instant;
+import org.apache.airavata.research.service.enums.EmailType;
+import org.hibernate.annotations.UuidGenerator;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.annotation.LastModifiedDate;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+
+@Entity(name = "EMAIL")
+@EntityListeners(AuditingEntityListener.class)
+public class EmailRecord {
+
+ @Id
+ @GeneratedValue
+ @UuidGenerator
+ @Column(nullable = false, updatable = false, length = 48)
+ private String id;
+
+ @Column(nullable = false)
+ private String userId;
+
+ @Column(nullable = false)
+ @Enumerated(EnumType.STRING)
+ private EmailType emailType;
+
+ @Column(nullable = false, updatable = false)
+ @CreatedDate
+ private Instant createdAt;
+
+ @Column(nullable = false)
+ @LastModifiedDate
+ private Instant updatedAt;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+
+ public EmailType getEmailType() {
+ return emailType;
+ }
+
+ public void setEmailType(EmailType emailType) {
+ this.emailType = emailType;
+ }
+
+ public Instant getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Instant createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public Instant getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(Instant updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+}
diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/EmailRecordRepository.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/EmailRecordRepository.java
new file mode 100644
index 0000000000..d81ae9005b
--- /dev/null
+++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/EmailRecordRepository.java
@@ -0,0 +1,32 @@
+/**
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+package org.apache.airavata.research.service.model.repo;
+
+import java.util.Optional;
+import org.apache.airavata.research.service.enums.EmailType;
+import org.apache.airavata.research.service.model.entity.EmailRecord;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface EmailRecordRepository extends JpaRepository {
+
+ Optional findByUserIdAndEmailType(String userId, EmailType emailType);
+}
diff --git a/modules/research-framework/research-service/src/main/resources/application.yml b/modules/research-framework/research-service/src/main/resources/application.yml
index 0652644a64..042101b531 100644
--- a/modules/research-framework/research-service/src/main/resources/application.yml
+++ b/modules/research-framework/research-service/src/main/resources/application.yml
@@ -31,6 +31,7 @@ airavata:
research-portal:
url: http://airavata.host:5173
dev-url: http://airavata.host:5173
+ admin-notification-email: "TO_EMAIL@gmail.com"
openid:
url: "http://airavata.host:18080/realms/default"
user-profile:
@@ -55,6 +56,17 @@ spring:
hibernate:
ddl-auto: update
open-in-view: false
+ mail:
+ host: smtp.gmail.com
+ port: 587
+ username: youremail@gmail.com
+ password: your-app-password # Use an App Password from Google
+ properties:
+ mail:
+ smtp:
+ auth: true
+ starttls:
+ enable: true
springdoc:
api-docs: