From aea4de56292b567fbe0c8dc6a3fe9263384c25da Mon Sep 17 00:00:00 2001 From: ganning127 Date: Sat, 19 Jul 2025 14:18:08 -0700 Subject: [PATCH 1/5] backend support for author roles --- .../service/config/DevDataInitializer.java | 64 +++++++++------ .../service/dto/CreateResourceRequest.java | 7 +- .../service/enums/AuthorRoleEnum.java | 28 +++++++ .../service/handlers/ResourceHandler.java | 31 ++++---- .../service/model/entity/Resource.java | 16 ++-- .../service/model/entity/ResourceAuthor.java | 79 +++++++++++++++++++ 6 files changed, 178 insertions(+), 47 deletions(-) create mode 100644 modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/enums/AuthorRoleEnum.java create mode 100644 modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/ResourceAuthor.java diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/config/DevDataInitializer.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/config/DevDataInitializer.java index ceb321fbbf..93d3b264f0 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/config/DevDataInitializer.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/config/DevDataInitializer.java @@ -19,6 +19,9 @@ */ package org.apache.airavata.research.service.config; +import static org.apache.airavata.research.service.enums.AuthorRoleEnum.PRIMARY; +import static org.apache.airavata.research.service.enums.StateEnum.ACTIVE; + import java.util.HashSet; import java.util.Set; import org.apache.airavata.research.service.enums.PrivacyEnum; @@ -26,6 +29,7 @@ import org.apache.airavata.research.service.model.entity.DatasetResource; import org.apache.airavata.research.service.model.entity.Project; import org.apache.airavata.research.service.model.entity.RepositoryResource; +import org.apache.airavata.research.service.model.entity.ResourceAuthor; import org.apache.airavata.research.service.model.entity.Tag; import org.apache.airavata.research.service.model.repo.ProjectRepository; import org.apache.airavata.research.service.model.repo.ResourceRepository; @@ -54,7 +58,7 @@ public DevDataInitializer( } private void createProject( - String name, String description, String repoUrl, String datasetUrl, String[] tags, String user) { + String name, String description, String repoUrl, String datasetUrl, String[] tags, Set authors) { Set tagSet = new HashSet<>(); for (String tag : tags) { Tag t = tagRepository.findByValue(tag); @@ -68,12 +72,6 @@ private void createProject( } } - Set authors = new HashSet<>() { - { - add(user); - } - }; - RepositoryResource repo = new RepositoryResource(); repo.setName(name); repo.setDescription(description); @@ -82,7 +80,16 @@ private void createProject( repo.setStatus(StatusEnum.VERIFIED); repo.setPrivacy(PrivacyEnum.PUBLIC); repo.setTags(tagSet); - repo.setAuthors(authors); + repo.setState(ACTIVE); + Set repoResourceAuthors = new HashSet<>(); + for (String author : authors) { + ResourceAuthor a = new ResourceAuthor(); + a.setResource(repo); + a.setRole(PRIMARY); + a.setAuthorId(author); + repoResourceAuthors.add(a); + } + repo.setAuthors(repoResourceAuthors); repo = resourceRepository.save(repo); DatasetResource dataset = new DatasetResource(); @@ -93,14 +100,24 @@ private void createProject( dataset.setStatus(StatusEnum.VERIFIED); dataset.setPrivacy(PrivacyEnum.PUBLIC); dataset.setTags(tagSet); - dataset.setAuthors(authors); + dataset.setState(ACTIVE); + Set datasetResourceAuthors = new HashSet<>(); + for (String author : authors) { + ResourceAuthor a = new ResourceAuthor(); + a.setResource(repo); + a.setRole(PRIMARY); + a.setAuthorId(author); + datasetResourceAuthors.add(a); + } + dataset.setAuthors(datasetResourceAuthors); dataset = resourceRepository.save(dataset); Project project = new Project(); project.setRepositoryResource(repo); project.getDatasetResources().add(dataset); project.setName(name); - project.setOwnerId(user); + project.setState(ACTIVE); + project.setOwnerId(String.join(", ", authors.stream().toString())); projectRepository.save(project); System.out.println("Initialized Project with id: " + project.getId()); @@ -108,18 +125,21 @@ private void createProject( @Override public void run(String... args) { + System.out.println("HRSDSF"); if (projectRepository.count() > 0) { System.out.println("Dev data already initialized. Skipping initialization."); return; } + System.out.println("Initializing dev data..."); + createProject( "Bio-realistic multiscale simulations of cortical circuits", "Running the AllenAI V1 model, with thalamacortical (LGN) and background (BKG) inputs", "https://github.com/cyber-shuttle/allenai-v1", "allenai-v1", new String[] {"neurodata25", "allenai", "visual_cortex"}, - "Anton Arkhipov, Laura Green"); + Set.of("Anton Arkhipov", "Laura Green")); createProject( "Apache Cerebrum", @@ -127,7 +147,7 @@ public void run(String... args) { "https://github.com/cyber-shuttle/airavata-cerebrum", "apache-airavata-cerebrum", new String[] {"neurodata25", "apache", "cerebrum"}, - "Sriram Chockalingam"); + Set.of("Sriram Chockalingam")); createProject( "Spatio-temporal dynamics of sleep in large-scale brain models", @@ -135,7 +155,7 @@ public void run(String... args) { "https://github.com/cyber-shuttle/whole-brain-public", "bazhlab-whole-brain", new String[] {"neurodata25", "bazhlab", "whole-brain"}, - "Maxim Bazhenov, Gabriela Navas Zuloaga"); + Set.of("Maxim Bazhenov", "Gabriela Navas Zuloaga")); createProject( "Biologically Constrained RNNs", @@ -143,7 +163,7 @@ public void run(String... args) { "https://github.com/cyber-shuttle/biologicalRNNs", "hchoilab-biologicalRNNs", new String[] {"neurodata25", "hchoilab", "biological-rnn"}, - "Hannah Choi, Aishwarya Balwani"); + Set.of("Hannah Choi", "Aishwarya Balwani")); createProject( "One-hot Generalized Linear Model for Switching Brain State Discovery", @@ -151,7 +171,7 @@ public void run(String... args) { "https://github.com/cyber-shuttle/onehot-hmmglm", "brainml-onehot-hmmglm", new String[] {"neurodata25", "brainml", "hmm-glm"}, - "Anqi Wu, Chengrui Li"); + Set.of("Anqi Wu", "Chengrui Li")); createProject( "Scaling up neural data analysis with torch_brain and temporaldata", @@ -159,7 +179,7 @@ public void run(String... args) { "https://github.com/cyber-shuttle/neurodata25_torchbrain_notebooks", "nerdslab-neurodata25", new String[] {"neurodata25", "nerdslab", "torch_brain", "temporaldata"}, - "Eva Dyer, Vinam Arora, Mahato Shivashriganesh"); + Set.of("Eva Dyer, Vinam Arora", "Mahato Shivashriganesh")); createProject( "Bridge the Gap between the Structure and Function in the Brain", @@ -167,7 +187,7 @@ public void run(String... args) { "https://github.com/cyber-shuttle/neuroaihub-netformer", "neuroaihub-netformer", new String[] {"neurodata25", "neuroaihub", "netformer"}, - "Lu Mi"); + Set.of("Lu Mi")); createProject( "Computing with Neural Oscillators", @@ -175,7 +195,7 @@ public void run(String... args) { "https://github.com/cyber-shuttle/imamlab-neural-oscillators", "imamlab-neurodata25", new String[] {"neurodata25", "imamlab", "neural-oscillators"}, - "Nabil Imam, Nand Chandravadia"); + Set.of("Nabil Imam, Nand Chandravadia")); createProject( "Getting started with Cybershuttle", @@ -183,7 +203,7 @@ public void run(String... args) { "https://github.com/cyber-shuttle/cybershuttle-reference", "cybershuttle-reference", new String[] {"cybershuttle", "apache-airavata", "reference"}, - "Suresh Marru"); + Set.of("Suresh Marru")); createProject( "Malicious URL Detector", @@ -191,7 +211,7 @@ public void run(String... args) { "https://github.com/airavata-courses/malicious-url-detector", "airavata-courses-malicious-url-detector", new String[] {"airavata-courses", "spring-2025"}, - "Krish Katariya, Jesse Gong, Shreyas Arisa, Devin Fromond"); + Set.of("Krish Katariya", "Jesse Gong", "Shreyas Arisa", "Devin Fromond")); createProject( "Deepseek Remote Execution", @@ -199,7 +219,7 @@ public void run(String... args) { "https://github.com/ZhenmeiOng/proj2-llama", "airavata-courses-deepseek-chat", new String[] {"airavata-courses", "spring-2025", "llm"}, - "Yashkaran Chauhan, Zhenmei Ong, Varenya Amagowni"); + Set.of("Yashkaran Chauhan", "Zhenmei Ong", "Varenya Amagowni")); createProject( "Fast Chat", @@ -207,6 +227,6 @@ public void run(String... args) { "https://github.com/riccog/cybershuttle", "airavata-courses-fast-chat", new String[] {"airavata-courses", "spring-2025"}, - "Ricco Goss, Mason Graham, Talam, Ruchira"); + Set.of("Ricco Goss", "Mason Graham", "Talam", "Ruchira")); } } diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/dto/CreateResourceRequest.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/dto/CreateResourceRequest.java index b3898febbe..c8b056640c 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/dto/CreateResourceRequest.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/dto/CreateResourceRequest.java @@ -21,6 +21,7 @@ import java.util.Set; import org.apache.airavata.research.service.enums.PrivacyEnum; +import org.apache.airavata.research.service.model.entity.ResourceAuthor; public class CreateResourceRequest { @@ -28,7 +29,7 @@ public class CreateResourceRequest { public String description; public String headerImage; Set tags; - Set authors; + Set authors; PrivacyEnum privacy; public PrivacyEnum getPrivacy() { @@ -39,11 +40,11 @@ public void setPrivacy(PrivacyEnum privacy) { this.privacy = privacy; } - public Set getAuthors() { + public Set getAuthors() { return authors; } - public void setAuthors(Set authors) { + public void setAuthors(Set authors) { this.authors = authors; } diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/enums/AuthorRoleEnum.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/enums/AuthorRoleEnum.java new file mode 100644 index 0000000000..f2609fe135 --- /dev/null +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/enums/AuthorRoleEnum.java @@ -0,0 +1,28 @@ +/** +* +* 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 AuthorRoleEnum { + PRIMARY, + SECONDARY, + TERTIARY, + QUATERNARY, + QUINARY +} diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java index 0e84a2b36f..958544253d 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java @@ -36,6 +36,7 @@ import org.apache.airavata.research.service.model.UserContext; import org.apache.airavata.research.service.model.entity.RepositoryResource; import org.apache.airavata.research.service.model.entity.Resource; +import org.apache.airavata.research.service.model.entity.ResourceAuthor; import org.apache.airavata.research.service.model.entity.ResourceStar; import org.apache.airavata.research.service.model.entity.Tag; import org.apache.airavata.research.service.model.repo.ProjectRepository; @@ -74,14 +75,18 @@ public ResourceHandler( } public void initializeResource(Resource resource) { - Set userSet = new HashSet<>(); - for (String authorId : resource.getAuthors()) { + Set userSet = new HashSet<>(); + for (ResourceAuthor author : resource.getAuthors()) { try { - UserProfile fetchedUser = airavataService.getUserProfile(authorId); - userSet.add(fetchedUser.getUserId()); + UserProfile fetchedUser = airavataService.getUserProfile(author.getAuthorId()); + ResourceAuthor newAuthor = new ResourceAuthor(); + newAuthor.setAuthorId(fetchedUser.getUserId()); + newAuthor.setRole(author.getRole()); + userSet.add(newAuthor); } catch (Exception e) { - LOGGER.error("Error while fetching user profile with the userId: {}", authorId, e); - throw new EntityNotFoundException("Error while fetching user profile with the userId: " + authorId, e); + LOGGER.error("Error while fetching user profile with the userId: {}", author.getAuthorId(), e); + throw new EntityNotFoundException( + "Error while fetching user profile with the userId: " + author.getAuthorId(), e); } } @@ -113,10 +118,10 @@ public void transferResourceRequestFields(Resource resource, CreateResourceReque // check that the logged in author is at least one of the authors making the request String currentUserId = UserContext.userId(); boolean found = false; - for (String authorId : createResourceRequest.getAuthors()) { - if (authorId.equalsIgnoreCase(currentUserId)) { + for (ResourceAuthor author : createResourceRequest.getAuthors()) { + author.setAuthorId(author.getAuthorId().toLowerCase()); + if (author.getAuthorId().equalsIgnoreCase(currentUserId)) { found = true; - break; } } if (!found) { @@ -126,9 +131,7 @@ public void transferResourceRequestFields(Resource resource, CreateResourceReque resource.setName(createResourceRequest.getName()); resource.setDescription(createResourceRequest.getDescription()); - resource.setAuthors(createResourceRequest.getAuthors().stream() - .map(String::toLowerCase) - .collect(Collectors.toSet())); + resource.setAuthors(createResourceRequest.getAuthors()); Set tagsSet = new HashSet<>(); for (String tag : createResourceRequest.getTags()) { org.apache.airavata.research.service.model.entity.Tag t = @@ -162,8 +165,8 @@ public Resource modifyResource(ModifyResourceRequest resourceRequest) { // ensure that the user making the request is one of the current authors boolean found = false; - for (String authorId : resource.getAuthors()) { - if (authorId.equalsIgnoreCase(UserContext.userId())) { + for (ResourceAuthor author : resource.getAuthors()) { + if (author.getAuthorId().equalsIgnoreCase(UserContext.userId())) { found = true; break; } diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/Resource.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/Resource.java index 97814f3163..b78cf72942 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/Resource.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/Resource.java @@ -19,10 +19,9 @@ */ package org.apache.airavata.research.service.model.entity; +import com.fasterxml.jackson.annotation.JsonManagedReference; import jakarta.persistence.CascadeType; -import jakarta.persistence.CollectionTable; import jakarta.persistence.Column; -import jakarta.persistence.ElementCollection; import jakarta.persistence.Entity; import jakarta.persistence.EntityListeners; import jakarta.persistence.EnumType; @@ -35,6 +34,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinTable; import jakarta.persistence.ManyToMany; +import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import java.time.Instant; import java.util.HashSet; @@ -69,10 +69,9 @@ public abstract class Resource { @Column(nullable = false) private String headerImage; - @ElementCollection(fetch = FetchType.EAGER) - @CollectionTable(name = "resource_authors", joinColumns = @JoinColumn(name = "resource_id")) - @Column(name = "author_id") - private Set authors = new HashSet<>(); + @OneToMany(mappedBy = "resource", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true) + @JsonManagedReference + private Set authors = new HashSet<>(); @ManyToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER) @JoinTable( @@ -135,11 +134,12 @@ public void setDescription(String description) { this.description = description; } - public Set getAuthors() { + public Set getAuthors() { return authors; } - public void setAuthors(Set authors) { + public void setAuthors(Set authors) { + authors.forEach(author -> author.setResource(this)); this.authors = authors; } diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/ResourceAuthor.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/ResourceAuthor.java new file mode 100644 index 0000000000..71ff006c2c --- /dev/null +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/ResourceAuthor.java @@ -0,0 +1,79 @@ +/** +* +* 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 com.fasterxml.jackson.annotation.JsonBackReference; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import org.apache.airavata.research.service.enums.AuthorRoleEnum; +import org.hibernate.annotations.UuidGenerator; + +@Entity +@Table(name = "resource_authors") +public class ResourceAuthor { + @Id + @GeneratedValue + @UuidGenerator + private String id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "resource_id", nullable = false) + @JsonBackReference + private Resource resource; + + @Column(name = "author_id") + private String authorId; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private AuthorRoleEnum role; + + public Resource getResource() { + return resource; + } + + public void setResource(Resource resource) { + this.resource = resource; + } + + public String getAuthorId() { + return authorId; + } + + public void setAuthorId(String authorId) { + this.authorId = authorId; + } + + public AuthorRoleEnum getRole() { + return role; + } + + public void setRole(AuthorRoleEnum role) { + this.role = role; + } +} From 21c1ffe1b1cf17b7d0e8b342942c50f514db29f4 Mon Sep 17 00:00:00 2001 From: ganning127 Date: Sun, 3 Aug 2025 13:42:52 -0700 Subject: [PATCH 2/5] merge --- .../service/config/DevDataInitializer.java | 36 +++++------ .../controller/ResourceController.java | 46 +++++++------- .../service/handlers/ResourceHandler.java | 60 ++++++++++++------- .../entity/ResourceVerificationActivity.java | 4 ++ .../src/main/resources/application.yml | 18 +++++- pom.xml | 8 +-- 6 files changed, 104 insertions(+), 68 deletions(-) create mode 100644 modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/ResourceVerificationActivity.java diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/config/DevDataInitializer.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/config/DevDataInitializer.java index 93d3b264f0..a369bbb13b 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/config/DevDataInitializer.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/config/DevDataInitializer.java @@ -1,22 +1,22 @@ /** -* -* 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. -*/ + * + * 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.config; import static org.apache.airavata.research.service.enums.AuthorRoleEnum.PRIMARY; diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/ResourceController.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/ResourceController.java index f02cf7cac5..2c46ca8325 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/ResourceController.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/ResourceController.java @@ -1,28 +1,25 @@ /** -* -* 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. -*/ + * 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.controller; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; -import java.util.ArrayList; -import java.util.List; import org.apache.airavata.research.service.dto.CreateResourceRequest; import org.apache.airavata.research.service.dto.ModifyResourceRequest; import org.apache.airavata.research.service.dto.ResourceResponse; @@ -49,6 +46,9 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import java.util.ArrayList; +import java.util.List; + @RestController @RequestMapping("/api/v1/rf/resources") @Tag(name = "Resources", description = "Datasets, notebooks, repositories, models") @@ -167,6 +167,12 @@ public ResponseEntity> getProjectsFromResourceId(@PathVariable(val return ResponseEntity.ok(projects); } + @Operation(summary = "Submit a resource for verification") + @PostMapping(value = "/{id}/verify") + public ResponseEntity submitResourceForVerification(@PathVariable(value = "id") String id) { + return ResponseEntity.ok(resourceHandler.submitResourceForVerification(id)); + } + @Operation(summary = "Star/unstar a resource") @PostMapping(value = "/{id}/star") public ResponseEntity starOrUnstarResource(@PathVariable(value = "id") String id) { diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java index 9664bf511c..cf5d98adfe 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java @@ -1,30 +1,24 @@ /** -* -* 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. -*/ + * 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.handlers; import jakarta.persistence.EntityNotFoundException; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; import org.apache.airavata.model.user.UserProfile; import org.apache.airavata.research.service.AiravataService; import org.apache.airavata.research.service.dto.CreateResourceRequest; @@ -52,6 +46,12 @@ import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + @Service public class ResourceHandler { @@ -296,6 +296,20 @@ public List getAllResourcesByTypeAndName(Class typ return resourceRepository.findByTypeAndNameContainingIgnoreCase(type, name.toLowerCase(), UserContext.userId()); } + public Resource submitResourceForVerification(String id) { + Resource resource = getResourceById(id); + String userId = UserContext.userId(); + + if (!resource.getAuthors().contains(userId.toLowerCase())) { + throw new IllegalArgumentException(String.format("User %s is not authorized to request verification for resource %s", userId, id)); + } + + resource.setStatus(StatusEnum.PENDING); + resourceRepository.save(resource); + + return resource; + } + private Page getAllPublicResources( int pageNumber, int pageSize, List> typeList, String[] tag, String nameSearch) { Pageable pageable = PageRequest.of(pageNumber, pageSize); diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/ResourceVerificationActivity.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/ResourceVerificationActivity.java new file mode 100644 index 0000000000..7da00ddd69 --- /dev/null +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/ResourceVerificationActivity.java @@ -0,0 +1,4 @@ +package org.apache.airavata.research.service.model.entity; + +public class ResourceVerificationActivity { +} 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..62170687d1 100644 --- a/modules/research-framework/research-service/src/main/resources/application.yml +++ b/modules/research-framework/research-service/src/main/resources/application.yml @@ -29,10 +29,11 @@ airavata: adminApiKey: "JUPYTER_ADMIN_API_KEY" limit: 10 research-portal: - url: http://airavata.host:5173 - dev-url: http://airavata.host:5173 + url: http://localhost:5173 + dev-url: http://localhost:5173 + admin-notification-email: "TO_EMAIL@gmail.com" openid: - url: "http://airavata.host:18080/realms/default" + url: "http://localhost:18080/realms/default" user-profile: server: url: airavata.host @@ -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: diff --git a/pom.xml b/pom.xml index edafd19681..a5d5ea9851 100644 --- a/pom.xml +++ b/pom.xml @@ -353,9 +353,9 @@ under the License. 2.1.3 - jakarta.transaction - jakarta.transaction-api - 2.0.1 + jakarta.transaction + jakarta.transaction-api + 2.0.1 javax.xml.bind @@ -612,7 +612,7 @@ under the License. ${skipTests} ${project.build.testOutputDirectory} false - -Xmx1024m -XX:MaxPermSize=256m --add-opens java.base/java.lang=ALL-UNNAMED + -Xmx1024m --add-opens java.base/java.lang=ALL-UNNAMED -javaagent:${settings.localRepository}/org/jmockit/jmockit/1.50/jmockit-1.50.jar false From 2d368d44f254e921e79e53e9bf45995355b5fda5 Mon Sep 17 00:00:00 2001 From: ganning127 Date: Sun, 10 Aug 2025 13:03:43 -0400 Subject: [PATCH 3/5] backend changes to support resource approval --- .../service/controller/AdminController.java | 55 +++++++++++ .../controller/ResourceController.java | 7 ++ .../service/handlers/AdminHandler.java | 77 +++++++++++++++ .../service/handlers/ResourceHandler.java | 57 ++++++++++- .../entity/ResourceVerificationActivity.java | 95 +++++++++++++++++++ .../model/repo/ResourceRepository.java | 90 +++++++++--------- ...esourceVerificationActivityRepository.java | 14 +++ .../src/main/resources/application.yml | 1 + 8 files changed, 349 insertions(+), 47 deletions(-) create mode 100644 modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/AdminController.java create mode 100644 modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/AdminHandler.java create mode 100644 modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceVerificationActivityRepository.java diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/AdminController.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/AdminController.java new file mode 100644 index 0000000000..5e3f9ef709 --- /dev/null +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/AdminController.java @@ -0,0 +1,55 @@ +package org.apache.airavata.research.service.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.apache.airavata.research.service.enums.StatusEnum; +import org.apache.airavata.research.service.handlers.AdminHandler; +import org.apache.airavata.research.service.handlers.ResourceHandler; +import org.apache.airavata.research.service.model.entity.Resource; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("/api/v1/rf/admin") +@Tag(name = "Admin Controls ", description = "Operations performable by Cybershuttle admins") +public class AdminController { + + private final ResourceHandler resourceHandler; + private final AdminHandler adminHandler; + + public AdminController(ResourceHandler resourceHandler, AdminHandler adminHandler) { + this.resourceHandler = resourceHandler; + this.adminHandler = adminHandler; + } + + @PostMapping("/resources/{id}/verify") + @Operation(summary = "Verify a resource") + public ResponseEntity verifyResource(@PathVariable(value = "id") String id) { + Resource resource = resourceHandler.getResourceById(id); + return ResponseEntity.ok(adminHandler.verifyResource(resource)); + } + + @PostMapping("/resources/{id}/reject") + @Operation(summary = "Verify a resource") + public ResponseEntity rejectResource(@PathVariable(value = "id") String id, @RequestBody String rejectionMessage) { + Resource resource = resourceHandler.getResourceById(id); + return ResponseEntity.ok(adminHandler.rejectResource(resource, rejectionMessage)); + } + + @GetMapping("/resources/pending") + @Operation(summary = "Get all pending verification resources") + public ResponseEntity> getPendingResources() { + return ResponseEntity.ok(resourceHandler.getAllResourcesWithStatus( + List.of(StatusEnum.PENDING) + )); + } + + +} diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/ResourceController.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/ResourceController.java index 2c46ca8325..2e4cde6507 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/ResourceController.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/ResourceController.java @@ -32,6 +32,7 @@ import org.apache.airavata.research.service.model.entity.Project; import org.apache.airavata.research.service.model.entity.RepositoryResource; import org.apache.airavata.research.service.model.entity.Resource; +import org.apache.airavata.research.service.model.entity.ResourceVerificationActivity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.domain.Page; @@ -173,6 +174,12 @@ public ResponseEntity submitResourceForVerification(@PathVariable(valu return ResponseEntity.ok(resourceHandler.submitResourceForVerification(id)); } + @Operation(summary = "Get verification activities for a resource") + @GetMapping(value = "/{id}/verification-activities") + public ResponseEntity> getResourceVerificationActivities(@PathVariable(value = "id") String id) { + return ResponseEntity.ok(resourceHandler.getResourceVerificationActivities(id)); + } + @Operation(summary = "Star/unstar a resource") @PostMapping(value = "/{id}/star") public ResponseEntity starOrUnstarResource(@PathVariable(value = "id") String id) { diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/AdminHandler.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/AdminHandler.java new file mode 100644 index 0000000000..7a681d4b4e --- /dev/null +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/AdminHandler.java @@ -0,0 +1,77 @@ +package org.apache.airavata.research.service.handlers; + +import org.apache.airavata.research.service.enums.StatusEnum; +import org.apache.airavata.research.service.model.UserContext; +import org.apache.airavata.research.service.model.entity.Resource; +import org.apache.airavata.research.service.model.entity.ResourceVerificationActivity; +import org.apache.airavata.research.service.model.repo.ResourceRepository; +import org.apache.airavata.research.service.model.repo.ResourceVerificationActivityRepository; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.Set; + +@Service +public class AdminHandler { + + private ResourceRepository resourceRepository; + private ResourceVerificationActivityRepository verificationActivityRepository; + + @Value("#{'${airavata.research-portal.admin-emails}'.split(',')}") + private Set cybershuttleAdminEmails; + + public AdminHandler( + ResourceRepository resourceRepository, + ResourceVerificationActivityRepository verificationActivityRepository + ) { + this.resourceRepository = resourceRepository; + this.verificationActivityRepository = verificationActivityRepository; + } + + public Resource verifyResource(Resource resource) { + if (resource.getStatus().equals(StatusEnum.VERIFIED)) { + return resource; + } + String userId = UserContext.userId(); + ensureAdminPermissions(userId); + + resource.setStatus(StatusEnum.VERIFIED); + resourceRepository.save(resource); + + ResourceVerificationActivity activity = new ResourceVerificationActivity(); + activity.setResource(resource); + activity.setUserId(userId); + activity.setStatus(StatusEnum.VERIFIED); + verificationActivityRepository.save(activity); + + return resource; + } + + public Resource rejectResource(Resource resource, String rejectionMessage) { + String userId = UserContext.userId(); + ensureAdminPermissions(userId); + String cleanMessage = rejectionMessage + .trim() + .replaceAll("\"", ""); + + resource.setStatus(StatusEnum.REJECTED); + resourceRepository.save(resource); + + ResourceVerificationActivity activity = new ResourceVerificationActivity(); + activity.setResource(resource); + activity.setUserId(userId); + activity.setMessage(cleanMessage); + activity.setStatus(StatusEnum.REJECTED); + verificationActivityRepository.save(activity); + + return resource; + } + + private void ensureAdminPermissions(String userId) { + if (!cybershuttleAdminEmails.contains(userId)) { + throw new RuntimeException(String.format("User %s does not have admin access in Cybershuttle", userId)); + } + } + + +} diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java index cf5d98adfe..4edaf0a487 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java @@ -33,13 +33,16 @@ import org.apache.airavata.research.service.model.entity.Resource; import org.apache.airavata.research.service.model.entity.ResourceAuthor; import org.apache.airavata.research.service.model.entity.ResourceStar; +import org.apache.airavata.research.service.model.entity.ResourceVerificationActivity; import org.apache.airavata.research.service.model.entity.Tag; import org.apache.airavata.research.service.model.repo.ProjectRepository; import org.apache.airavata.research.service.model.repo.ResourceRepository; import org.apache.airavata.research.service.model.repo.ResourceStarRepository; +import org.apache.airavata.research.service.model.repo.ResourceVerificationActivityRepository; import org.apache.airavata.research.service.model.repo.TagRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -62,18 +65,25 @@ public class ResourceHandler { private final ResourceRepository resourceRepository; private final ProjectRepository projectRepository; private final ResourceStarRepository resourceStarRepository; + private final ResourceVerificationActivityRepository verificationActivityRepository; + + @Value("#{'${airavata.research-portal.admin-emails}'.split(',')}") + private Set cybershuttleAdminEmails; public ResourceHandler( AiravataService airavataService, TagRepository tagRepository, ResourceRepository resourceRepository, ProjectRepository projectRepository, - ResourceStarRepository resourceStarRepository) { + ResourceStarRepository resourceStarRepository, + ResourceVerificationActivityRepository verificationActivityRepository + ) { this.airavataService = airavataService; this.tagRepository = tagRepository; this.resourceRepository = resourceRepository; this.projectRepository = projectRepository; this.resourceStarRepository = resourceStarRepository; + this.verificationActivityRepository = verificationActivityRepository; } public void initializeResource(Resource resource) { @@ -241,7 +251,11 @@ public Resource getResourceById(String id) { if (resource.getPrivacy().equals(PrivacyEnum.PUBLIC)) { return resource; } else if (isAuthenticated - && resource.getAuthors().contains(UserContext.userId().toLowerCase())) { + && resource + .getAuthors() + .stream() + .map(ResourceAuthor::getAuthorId) + .anyMatch(authorId -> authorId.equals(UserContext.userId().toLowerCase()))) { return resource; } else { throw new EntityNotFoundException("Resource not found: " + id); @@ -258,7 +272,12 @@ public boolean deleteResourceById(String id) { Resource resource = opResource.get(); String userEmail = UserContext.userId(); - if (!resource.getAuthors().contains(userEmail.toLowerCase())) { + if (!resource + .getAuthors() + .stream() + .map(ResourceAuthor::getAuthorId) + .anyMatch(authorId -> authorId.equals(UserContext.userId().toLowerCase())) + ) { String errorMsg = String.format( "User %s not authorized to delete resource: %s (%s), type: %s", userEmail, resource.getName(), id, resource.getType().toString()); @@ -300,16 +319,39 @@ public Resource submitResourceForVerification(String id) { Resource resource = getResourceById(id); String userId = UserContext.userId(); - if (!resource.getAuthors().contains(userId.toLowerCase())) { + if (!isResourceAuthor(resource, userId)) { throw new IllegalArgumentException(String.format("User %s is not authorized to request verification for resource %s", userId, id)); } resource.setStatus(StatusEnum.PENDING); resourceRepository.save(resource); + ResourceVerificationActivity activity = new ResourceVerificationActivity(); + activity.setResource(resource); + activity.setUserId(userId); + activity.setStatus(StatusEnum.PENDING); + verificationActivityRepository.save(activity); + return resource; } + public List getResourceVerificationActivities(String id) { + Resource resource = getResourceById(id); + String userId = UserContext.userId(); + + if (!isResourceAuthor(resource, userId) && !cybershuttleAdminEmails.contains(userId.toLowerCase())) { + throw new IllegalArgumentException(String.format("User %s is not authorized to pull verification activities for resource %s", userId, id)); + } + + return verificationActivityRepository.findAllByResourceOrderByUpdatedAtDesc(resource); + } + + public List getAllResourcesWithStatus(List includeStatus) { + return resourceRepository.findAllByStatusInOrderByCreatedAtDesc( + includeStatus + ); + } + private Page getAllPublicResources( int pageNumber, int pageSize, List> typeList, String[] tag, String nameSearch) { Pageable pageable = PageRequest.of(pageNumber, pageSize); @@ -337,4 +379,11 @@ private Page getAllResourcesUserSignedIn( return resourceRepository.findAllByTypesAndAllTagsForUser( typeList, tag, (long) tag.length, nameSearch.toLowerCase(), userId, pageable); } + + private boolean isResourceAuthor(Resource resource, String userId) { + return resource.getAuthors() + .stream() + .map(ResourceAuthor::getAuthorId) + .anyMatch(userId::equals); + } } diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/ResourceVerificationActivity.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/ResourceVerificationActivity.java index 7da00ddd69..597c256f9f 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/ResourceVerificationActivity.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/ResourceVerificationActivity.java @@ -1,4 +1,99 @@ package org.apache.airavata.research.service.model.entity; +import com.fasterxml.jackson.annotation.JsonBackReference; +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 jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import org.apache.airavata.research.service.enums.StatusEnum; +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; + +import java.time.Instant; + +@Entity(name = "RESOURCE_VERIFICATION_ACTIVITY") +@EntityListeners(AuditingEntityListener.class) public class ResourceVerificationActivity { + + @Id + @GeneratedValue + @UuidGenerator + @Column(nullable = false, updatable = false, length = 48) + private String id; + + @ManyToOne(optional = false) + @JoinColumn(name = "resource_id") + @JsonBackReference + private Resource resource; + + @Column(name = "user_id", nullable = false) + private String userId; // can't use ResourceAuthor because admins are not authors, and they can also make activities + + @Column(nullable = false) + @Enumerated(EnumType.STRING) + private StatusEnum status; + + @Column + private String message; + + @Column(nullable = false, updatable = false) + @CreatedDate + private Instant createdAt; + + @Column(nullable = false) + @LastModifiedDate + private Instant updatedAt; + + + public String getId() { + return id; + } + + public Resource getResource() { + return resource; + } + + public void setResource(Resource resource) { + this.resource = resource; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public StatusEnum getStatus() { + return status; + } + + public void setStatus(StatusEnum status) { + this.status = status; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Instant getCreatedAt() { + return createdAt; + } + + public Instant getUpdatedAt() { + return updatedAt; + } + } diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceRepository.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceRepository.java index 98e7b27a2f..6ef5efb793 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceRepository.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceRepository.java @@ -1,27 +1,25 @@ /** -* -* 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. -*/ + * 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.List; -import java.util.Optional; import org.apache.airavata.research.service.enums.StateEnum; +import org.apache.airavata.research.service.enums.StatusEnum; import org.apache.airavata.research.service.model.entity.Resource; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -30,6 +28,10 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + @Repository public interface ResourceRepository extends JpaRepository { @@ -50,15 +52,15 @@ Page findAllByTypes( @Query( """ - SELECT DISTINCT r - FROM Resource r - JOIN r.authors a - WHERE r.class IN :typeList - AND LOWER(r.name) LIKE LOWER(CONCAT('%', :nameSearch, '%')) - AND r.state = 'ACTIVE' - AND (r.privacy = 'PUBLIC' or a = :userId) - ORDER BY r.name - """) + SELECT DISTINCT r + FROM Resource r + JOIN r.authors a + WHERE r.class IN :typeList + AND LOWER(r.name) LIKE LOWER(CONCAT('%', :nameSearch, '%')) + AND r.state = 'ACTIVE' + AND (r.privacy = 'PUBLIC' or a.authorId = :userId) + ORDER BY r.name + """) Page findAllByTypesForUser( @Param("typeList") List> typeList, @Param("nameSearch") String nameSearch, @@ -88,19 +90,19 @@ Page findAllByTypesAndAllTags( @Query( """ - SELECT r - FROM Resource r - JOIN r.tags t - JOIN r.authors a - WHERE r.class IN :typeList - AND t.value IN :tags - AND LOWER(r.name) LIKE LOWER(CONCAT('%', :nameSearch, '%')) - AND r.state = 'ACTIVE' - AND (r.privacy = 'PUBLIC' OR a = :userId) - GROUP BY r - HAVING COUNT(DISTINCT t.value) = :tagCount - ORDER BY r.name - """) + SELECT r + FROM Resource r + JOIN r.tags t + JOIN r.authors a + WHERE r.class IN :typeList + AND t.value IN :tags + AND LOWER(r.name) LIKE LOWER(CONCAT('%', :nameSearch, '%')) + AND r.state = 'ACTIVE' + AND (r.privacy = 'PUBLIC' OR a.authorId = :userId) + GROUP BY r + HAVING COUNT(DISTINCT t.value) = :tagCount + ORDER BY r.name + """) Page findAllByTypesAndAllTagsForUser( @Param("typeList") List> typeList, @Param("tags") String[] tags, @@ -116,10 +118,12 @@ Page findAllByTypesAndAllTagsForUser( JOIN r.authors a WHERE TYPE(r) = :type AND r.state = 'ACTIVE' AND LOWER(r.name) LIKE LOWER(CONCAT('%', :name, '%')) - AND (r.privacy = "PUBLIC" OR a = :userId) + AND (r.privacy = "PUBLIC" OR a.authorId = :userId) """) List findByTypeAndNameContainingIgnoreCase( @Param("type") Class type, @Param("name") String name, @Param("userId") String userId); Optional findByIdAndState(String id, StateEnum state); + + List findAllByStatusInOrderByCreatedAtDesc(Collection statuses); } diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceVerificationActivityRepository.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceVerificationActivityRepository.java new file mode 100644 index 0000000000..b8078da027 --- /dev/null +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceVerificationActivityRepository.java @@ -0,0 +1,14 @@ +package org.apache.airavata.research.service.model.repo; + +import org.apache.airavata.research.service.model.entity.Resource; +import org.apache.airavata.research.service.model.entity.ResourceVerificationActivity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +public interface ResourceVerificationActivityRepository extends JpaRepository, JpaSpecificationExecutor { + + List findAllByResourceOrderByUpdatedAtDesc(Resource resource); + +} 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 62170687d1..8f1bde858b 100644 --- a/modules/research-framework/research-service/src/main/resources/application.yml +++ b/modules/research-framework/research-service/src/main/resources/application.yml @@ -32,6 +32,7 @@ airavata: url: http://localhost:5173 dev-url: http://localhost:5173 admin-notification-email: "TO_EMAIL@gmail.com" + admin-emails: ganning.xu@gatech.edu,ljayathilake3@gatech.edu,yasith@gatech.edu,smarru@gatech.edu,dimuthuw@gatech.edu openid: url: "http://localhost:18080/realms/default" user-profile: From 619beb11e1565dc15a91759796042dddd8f654cf Mon Sep 17 00:00:00 2001 From: ganning127 Date: Sun, 10 Aug 2025 13:04:13 -0400 Subject: [PATCH 4/5] spotless --- .../service/controller/AdminController.java | 31 +++++-- .../controller/ResourceController.java | 43 +++++----- .../service/handlers/AdminHandler.java | 31 ++++--- .../service/handlers/ResourceHandler.java | 80 +++++++++---------- .../entity/ResourceVerificationActivity.java | 24 +++++- .../model/repo/ResourceRepository.java | 42 +++++----- ...esourceVerificationActivityRepository.java | 27 ++++++- 7 files changed, 167 insertions(+), 111 deletions(-) diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/AdminController.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/AdminController.java index 5e3f9ef709..74c9d005dc 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/AdminController.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/AdminController.java @@ -1,7 +1,27 @@ +/** +* +* 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.controller; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; import org.apache.airavata.research.service.enums.StatusEnum; import org.apache.airavata.research.service.handlers.AdminHandler; import org.apache.airavata.research.service.handlers.ResourceHandler; @@ -14,8 +34,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import java.util.List; - @RestController @RequestMapping("/api/v1/rf/admin") @Tag(name = "Admin Controls ", description = "Operations performable by Cybershuttle admins") @@ -38,7 +56,8 @@ public ResponseEntity verifyResource(@PathVariable(value = "id") Strin @PostMapping("/resources/{id}/reject") @Operation(summary = "Verify a resource") - public ResponseEntity rejectResource(@PathVariable(value = "id") String id, @RequestBody String rejectionMessage) { + public ResponseEntity rejectResource( + @PathVariable(value = "id") String id, @RequestBody String rejectionMessage) { Resource resource = resourceHandler.getResourceById(id); return ResponseEntity.ok(adminHandler.rejectResource(resource, rejectionMessage)); } @@ -46,10 +65,6 @@ public ResponseEntity rejectResource(@PathVariable(value = "id") Strin @GetMapping("/resources/pending") @Operation(summary = "Get all pending verification resources") public ResponseEntity> getPendingResources() { - return ResponseEntity.ok(resourceHandler.getAllResourcesWithStatus( - List.of(StatusEnum.PENDING) - )); + return ResponseEntity.ok(resourceHandler.getAllResourcesWithStatus(List.of(StatusEnum.PENDING))); } - - } diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/ResourceController.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/ResourceController.java index 2e4cde6507..65469e54c5 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/ResourceController.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/controller/ResourceController.java @@ -1,25 +1,28 @@ /** - * 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. - */ +* +* 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.controller; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.ArrayList; +import java.util.List; import org.apache.airavata.research.service.dto.CreateResourceRequest; import org.apache.airavata.research.service.dto.ModifyResourceRequest; import org.apache.airavata.research.service.dto.ResourceResponse; @@ -47,9 +50,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import java.util.ArrayList; -import java.util.List; - @RestController @RequestMapping("/api/v1/rf/resources") @Tag(name = "Resources", description = "Datasets, notebooks, repositories, models") @@ -176,7 +176,8 @@ public ResponseEntity submitResourceForVerification(@PathVariable(valu @Operation(summary = "Get verification activities for a resource") @GetMapping(value = "/{id}/verification-activities") - public ResponseEntity> getResourceVerificationActivities(@PathVariable(value = "id") String id) { + public ResponseEntity> getResourceVerificationActivities( + @PathVariable(value = "id") String id) { return ResponseEntity.ok(resourceHandler.getResourceVerificationActivities(id)); } diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/AdminHandler.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/AdminHandler.java index 7a681d4b4e..1773446042 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/AdminHandler.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/AdminHandler.java @@ -1,5 +1,25 @@ +/** +* +* 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.handlers; +import java.util.Set; import org.apache.airavata.research.service.enums.StatusEnum; import org.apache.airavata.research.service.model.UserContext; import org.apache.airavata.research.service.model.entity.Resource; @@ -9,8 +29,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import java.util.Set; - @Service public class AdminHandler { @@ -22,8 +40,7 @@ public class AdminHandler { public AdminHandler( ResourceRepository resourceRepository, - ResourceVerificationActivityRepository verificationActivityRepository - ) { + ResourceVerificationActivityRepository verificationActivityRepository) { this.resourceRepository = resourceRepository; this.verificationActivityRepository = verificationActivityRepository; } @@ -50,9 +67,7 @@ public Resource verifyResource(Resource resource) { public Resource rejectResource(Resource resource, String rejectionMessage) { String userId = UserContext.userId(); ensureAdminPermissions(userId); - String cleanMessage = rejectionMessage - .trim() - .replaceAll("\"", ""); + String cleanMessage = rejectionMessage.trim().replaceAll("\"", ""); resource.setStatus(StatusEnum.REJECTED); resourceRepository.save(resource); @@ -72,6 +87,4 @@ private void ensureAdminPermissions(String userId) { throw new RuntimeException(String.format("User %s does not have admin access in Cybershuttle", userId)); } } - - } diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java index 4edaf0a487..b43936e819 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/handlers/ResourceHandler.java @@ -1,24 +1,30 @@ /** - * 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. - */ +* +* 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.handlers; import jakarta.persistence.EntityNotFoundException; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; import org.apache.airavata.model.user.UserProfile; import org.apache.airavata.research.service.AiravataService; import org.apache.airavata.research.service.dto.CreateResourceRequest; @@ -49,12 +55,6 @@ import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - @Service public class ResourceHandler { @@ -76,8 +76,7 @@ public ResourceHandler( ResourceRepository resourceRepository, ProjectRepository projectRepository, ResourceStarRepository resourceStarRepository, - ResourceVerificationActivityRepository verificationActivityRepository - ) { + ResourceVerificationActivityRepository verificationActivityRepository) { this.airavataService = airavataService; this.tagRepository = tagRepository; this.resourceRepository = resourceRepository; @@ -251,11 +250,10 @@ public Resource getResourceById(String id) { if (resource.getPrivacy().equals(PrivacyEnum.PUBLIC)) { return resource; } else if (isAuthenticated - && resource - .getAuthors() - .stream() - .map(ResourceAuthor::getAuthorId) - .anyMatch(authorId -> authorId.equals(UserContext.userId().toLowerCase()))) { + && resource.getAuthors().stream() + .map(ResourceAuthor::getAuthorId) + .anyMatch( + authorId -> authorId.equals(UserContext.userId().toLowerCase()))) { return resource; } else { throw new EntityNotFoundException("Resource not found: " + id); @@ -272,12 +270,9 @@ public boolean deleteResourceById(String id) { Resource resource = opResource.get(); String userEmail = UserContext.userId(); - if (!resource - .getAuthors() - .stream() + if (!resource.getAuthors().stream() .map(ResourceAuthor::getAuthorId) - .anyMatch(authorId -> authorId.equals(UserContext.userId().toLowerCase())) - ) { + .anyMatch(authorId -> authorId.equals(UserContext.userId().toLowerCase()))) { String errorMsg = String.format( "User %s not authorized to delete resource: %s (%s), type: %s", userEmail, resource.getName(), id, resource.getType().toString()); @@ -320,7 +315,8 @@ public Resource submitResourceForVerification(String id) { String userId = UserContext.userId(); if (!isResourceAuthor(resource, userId)) { - throw new IllegalArgumentException(String.format("User %s is not authorized to request verification for resource %s", userId, id)); + throw new IllegalArgumentException( + String.format("User %s is not authorized to request verification for resource %s", userId, id)); } resource.setStatus(StatusEnum.PENDING); @@ -340,16 +336,15 @@ public List getResourceVerificationActivities(Stri String userId = UserContext.userId(); if (!isResourceAuthor(resource, userId) && !cybershuttleAdminEmails.contains(userId.toLowerCase())) { - throw new IllegalArgumentException(String.format("User %s is not authorized to pull verification activities for resource %s", userId, id)); + throw new IllegalArgumentException(String.format( + "User %s is not authorized to pull verification activities for resource %s", userId, id)); } return verificationActivityRepository.findAllByResourceOrderByUpdatedAtDesc(resource); } public List getAllResourcesWithStatus(List includeStatus) { - return resourceRepository.findAllByStatusInOrderByCreatedAtDesc( - includeStatus - ); + return resourceRepository.findAllByStatusInOrderByCreatedAtDesc(includeStatus); } private Page getAllPublicResources( @@ -381,9 +376,6 @@ private Page getAllResourcesUserSignedIn( } private boolean isResourceAuthor(Resource resource, String userId) { - return resource.getAuthors() - .stream() - .map(ResourceAuthor::getAuthorId) - .anyMatch(userId::equals); + return resource.getAuthors().stream().map(ResourceAuthor::getAuthorId).anyMatch(userId::equals); } } diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/ResourceVerificationActivity.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/ResourceVerificationActivity.java index 597c256f9f..355bb66321 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/ResourceVerificationActivity.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/entity/ResourceVerificationActivity.java @@ -1,3 +1,22 @@ +/** +* +* 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 com.fasterxml.jackson.annotation.JsonBackReference; @@ -10,14 +29,13 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; +import java.time.Instant; import org.apache.airavata.research.service.enums.StatusEnum; 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; -import java.time.Instant; - @Entity(name = "RESOURCE_VERIFICATION_ACTIVITY") @EntityListeners(AuditingEntityListener.class) public class ResourceVerificationActivity { @@ -51,7 +69,6 @@ public class ResourceVerificationActivity { @LastModifiedDate private Instant updatedAt; - public String getId() { return id; } @@ -95,5 +112,4 @@ public Instant getCreatedAt() { public Instant getUpdatedAt() { return updatedAt; } - } diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceRepository.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceRepository.java index 6ef5efb793..30c998ac70 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceRepository.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceRepository.java @@ -1,23 +1,27 @@ /** - * 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. - */ +* +* 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.Collection; +import java.util.List; +import java.util.Optional; import org.apache.airavata.research.service.enums.StateEnum; import org.apache.airavata.research.service.enums.StatusEnum; import org.apache.airavata.research.service.model.entity.Resource; @@ -28,10 +32,6 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.Collection; -import java.util.List; -import java.util.Optional; - @Repository public interface ResourceRepository extends JpaRepository { diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceVerificationActivityRepository.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceVerificationActivityRepository.java index b8078da027..a9ca261844 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceVerificationActivityRepository.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/model/repo/ResourceVerificationActivityRepository.java @@ -1,14 +1,33 @@ +/** +* +* 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.List; import org.apache.airavata.research.service.model.entity.Resource; import org.apache.airavata.research.service.model.entity.ResourceVerificationActivity; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -import java.util.List; - -public interface ResourceVerificationActivityRepository extends JpaRepository, JpaSpecificationExecutor { +public interface ResourceVerificationActivityRepository + extends JpaRepository, + JpaSpecificationExecutor { List findAllByResourceOrderByUpdatedAtDesc(Resource resource); - } From d707212031f6c0019b991c55aa3e5568e3fdbd6c Mon Sep 17 00:00:00 2001 From: ganning127 Date: Sun, 10 Aug 2025 13:05:05 -0400 Subject: [PATCH 5/5] more spotless --- .../service/config/DevDataInitializer.java | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/config/DevDataInitializer.java b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/config/DevDataInitializer.java index a369bbb13b..93d3b264f0 100644 --- a/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/config/DevDataInitializer.java +++ b/modules/research-framework/research-service/src/main/java/org/apache/airavata/research/service/config/DevDataInitializer.java @@ -1,22 +1,22 @@ /** - * - * 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. - */ +* +* 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.config; import static org.apache.airavata.research.service.enums.AuthorRoleEnum.PRIMARY;