From 9cfb5ddaafd4df46030c195bea78a26ef1c4ce9d Mon Sep 17 00:00:00 2001 From: Juan Carlos Namendi Pineda Date: Wed, 29 Nov 2023 13:47:03 +0700 Subject: [PATCH 01/20] ATL-9: Tools Module --- src/main/java/org/ohdsi/webapi/tool/Tool.java | 83 ++++++++++++++ .../org/ohdsi/webapi/tool/ToolController.java | 55 +++++++++ .../org/ohdsi/webapi/tool/ToolRepository.java | 8 ++ .../org/ohdsi/webapi/tool/ToolService.java | 13 +++ .../ohdsi/webapi/tool/ToolServiceImpl.java | 69 ++++++++++++ .../webapi/tool/converter/ToolConvertor.java | 81 ++++++++++++++ .../org/ohdsi/webapi/tool/dto/ToolDTO.java | 104 ++++++++++++++++++ .../java/org/ohdsi/webapi/util/DateUtils.java | 16 +++ ...8.0.20231205141300__create_table_tools.sql | 35 ++++++ ...3.1.20231213141052__create_table_tools.sql | 18 +++ .../V20231213151942__create_table_tools.sql | 18 +++ src/main/resources/i18n/messages_en.json | 38 ++++++- src/main/resources/i18n/messages_ko.json | 38 ++++++- src/main/resources/i18n/messages_ru.json | 38 ++++++- src/main/resources/i18n/messages_zh.json | 38 ++++++- 15 files changed, 644 insertions(+), 8 deletions(-) create mode 100644 src/main/java/org/ohdsi/webapi/tool/Tool.java create mode 100644 src/main/java/org/ohdsi/webapi/tool/ToolController.java create mode 100644 src/main/java/org/ohdsi/webapi/tool/ToolRepository.java create mode 100644 src/main/java/org/ohdsi/webapi/tool/ToolService.java create mode 100644 src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java create mode 100644 src/main/java/org/ohdsi/webapi/tool/converter/ToolConvertor.java create mode 100644 src/main/java/org/ohdsi/webapi/tool/dto/ToolDTO.java create mode 100644 src/main/java/org/ohdsi/webapi/util/DateUtils.java create mode 100644 src/main/resources/db/migration/oracle/V2.8.0.20231205141300__create_table_tools.sql create mode 100644 src/main/resources/db/migration/postgresql/V2.13.1.20231213141052__create_table_tools.sql create mode 100644 src/main/resources/db/migration/sqlserver/V20231213151942__create_table_tools.sql diff --git a/src/main/java/org/ohdsi/webapi/tool/Tool.java b/src/main/java/org/ohdsi/webapi/tool/Tool.java new file mode 100644 index 0000000000..5da5393aec --- /dev/null +++ b/src/main/java/org/ohdsi/webapi/tool/Tool.java @@ -0,0 +1,83 @@ +package org.ohdsi.webapi.tool; + +import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.Parameter; +import org.ohdsi.webapi.model.CommonEntity; + +import javax.persistence.*; +import java.util.Objects; + +@Entity +@Table(name = "tool") +public class Tool extends CommonEntity { + @Id + @GenericGenerator( + name = "tool_generator", + strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator", + parameters = { + @Parameter(name = "sequence_name", value = "tool_seq"), + @Parameter(name = "increment_size", value = "1") + } + ) + @GeneratedValue(generator = "tool_generator") + private Integer id; + private String name; + private String url; + private String description; + @Column(name = "is_enabled") + private Boolean isEnabled; + + @Override + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Boolean getEnabled() { + return isEnabled; + } + + public void setEnabled(Boolean enabled) { + isEnabled = enabled; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Tool tool = (Tool) o; + return Objects.equals(name, tool.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } +} diff --git a/src/main/java/org/ohdsi/webapi/tool/ToolController.java b/src/main/java/org/ohdsi/webapi/tool/ToolController.java new file mode 100644 index 0000000000..362a5bf81a --- /dev/null +++ b/src/main/java/org/ohdsi/webapi/tool/ToolController.java @@ -0,0 +1,55 @@ +package org.ohdsi.webapi.tool; + +import org.ohdsi.webapi.tool.dto.ToolDTO; +import org.springframework.stereotype.Controller; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import java.util.List; + +@Controller +@Path("/tool") +public class ToolController { + private final ToolService service; + + public ToolController(ToolService service) { + this.service = service; + } + + @GET + @Path("") + @Produces(MediaType.APPLICATION_JSON) + public List getTools() { + return service.getTools(); + } + + @GET + @Path("/{id}") + @Produces(MediaType.APPLICATION_JSON) + public ToolDTO getToolById(@PathParam("id") Integer id) { + return service.getById(id); + } + + @POST + @Path("") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public ToolDTO createTool(ToolDTO dto) { + return service.saveTool(dto); + } + + @DELETE + @Path("/{id}") + @Produces(MediaType.APPLICATION_JSON) + public void delete(@PathParam("id") Integer id) { + service.delete(id); + } + + @PUT + @Path("") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public ToolDTO updateTool(ToolDTO toolDTO) { + return service.saveTool(toolDTO); + } +} diff --git a/src/main/java/org/ohdsi/webapi/tool/ToolRepository.java b/src/main/java/org/ohdsi/webapi/tool/ToolRepository.java new file mode 100644 index 0000000000..ebe624f438 --- /dev/null +++ b/src/main/java/org/ohdsi/webapi/tool/ToolRepository.java @@ -0,0 +1,8 @@ +package org.ohdsi.webapi.tool; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ToolRepository extends JpaRepository { +} diff --git a/src/main/java/org/ohdsi/webapi/tool/ToolService.java b/src/main/java/org/ohdsi/webapi/tool/ToolService.java new file mode 100644 index 0000000000..32501d4c48 --- /dev/null +++ b/src/main/java/org/ohdsi/webapi/tool/ToolService.java @@ -0,0 +1,13 @@ +package org.ohdsi.webapi.tool; + +import org.ohdsi.webapi.tool.dto.ToolDTO; + +import java.util.List; + +public interface ToolService { + List getTools(); + ToolDTO saveTool(ToolDTO toolDTO); + ToolDTO getById(Integer id); + + void delete(Integer id); +} diff --git a/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java b/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java new file mode 100644 index 0000000000..eb42e9aad1 --- /dev/null +++ b/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java @@ -0,0 +1,69 @@ +package org.ohdsi.webapi.tool; + +import org.ohdsi.webapi.service.AbstractDaoService; +import org.ohdsi.webapi.shiro.Entities.UserEntity; +import org.ohdsi.webapi.shiro.PermissionManager; +import org.ohdsi.webapi.tool.converter.ToolConvertor; +import org.ohdsi.webapi.tool.dto.ToolDTO; +import org.springframework.stereotype.Service; + +import javax.ws.rs.ForbiddenException; +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class ToolServiceImpl extends AbstractDaoService implements ToolService { + private final ToolRepository toolRepository; + private final ToolConvertor toolConvertor; + private final PermissionManager permissionManager; + + public ToolServiceImpl(ToolRepository toolRepository, ToolConvertor toolConvertor, PermissionManager permissionManager) { + this.toolRepository = toolRepository; + this.toolConvertor = toolConvertor; + this.permissionManager = permissionManager; + } + + @Override + public List getTools() { + return toolRepository.findAll().stream() + .map(tool -> { + ToolDTO dto = toolConvertor.toDTO(tool); + UserEntity userById = permissionManager.getUserById(tool.getCreatedBy().getId()); + dto.setCreatedByName(userById.getName()); + return dto; + }).collect(Collectors.toList()); + } + + @Override + public ToolDTO saveTool(ToolDTO toolDTO) { + if (!isAdmin()) { + throw new ForbiddenException(); + } + UserEntity currentUser = permissionManager.getCurrentUser(); + Tool tool = updateToolFromDTO(toolDTO, currentUser); + return toolConvertor.toDTO(toolRepository.saveAndFlush(tool)); + } + + private Tool updateToolFromDTO(ToolDTO toolDTO, UserEntity currentUser) { + Tool tool = toolConvertor.toEntity(toolDTO); + if (toolDTO.getId() == null) { + tool.setCreatedBy(currentUser); + } + tool.setModifiedBy(currentUser); + return tool; + } + + @Override + public ToolDTO getById(Integer id) { + return toolConvertor.toDTO(toolRepository.findOne(id)); + } + + @Override + public void delete(Integer id) { + if (isAdmin()) { + toolRepository.delete(id); + } else { + throw new ForbiddenException(); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/ohdsi/webapi/tool/converter/ToolConvertor.java b/src/main/java/org/ohdsi/webapi/tool/converter/ToolConvertor.java new file mode 100644 index 0000000000..6fd9b452b2 --- /dev/null +++ b/src/main/java/org/ohdsi/webapi/tool/converter/ToolConvertor.java @@ -0,0 +1,81 @@ +package org.ohdsi.webapi.tool.converter; + +import org.ohdsi.webapi.service.AbstractDaoService; +import org.ohdsi.webapi.shiro.Entities.UserEntity; +import org.ohdsi.webapi.shiro.PermissionManager; +import org.ohdsi.webapi.tool.Tool; +import org.ohdsi.webapi.tool.ToolRepository; +import org.ohdsi.webapi.tool.dto.ToolDTO; +import org.ohdsi.webapi.util.DateUtils; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.util.Date; +import java.util.Optional; + +@Component +public class ToolConvertor extends AbstractDaoService { + private final ToolRepository toolRepository; + private final PermissionManager permissionManager; + + public ToolConvertor(ToolRepository toolRepository, PermissionManager permissionManager) { + this.toolRepository = toolRepository; + this.permissionManager = permissionManager; + } + + public Tool toEntity(ToolDTO toolDTO) { + boolean isNewTool = toolDTO.getId() == null; + Tool tool = isNewTool ? new Tool() : toolRepository.findOne(toolDTO.getId()); + Instant currentInstant = Instant.now(); + if (isNewTool) { + setCreationDetails(tool, currentInstant); + } else { + setModificationDetails(tool, currentInstant); + } + updateToolFromDTO(tool, toolDTO); + return tool; + } + + private void setCreationDetails(Tool tool, Instant currentInstant) { + tool.setCreatedDate(Date.from(currentInstant)); + tool.setCreatedBy(getCurrentUser()); + } + + private void setModificationDetails(Tool tool, Instant currentInstant) { + tool.setModifiedDate(Date.from(currentInstant)); + tool.setModifiedBy(getCurrentUser()); + } + + private void updateToolFromDTO(Tool tool, ToolDTO toolDTO) { + Optional.ofNullable(toolDTO.getName()).ifPresent(tool::setName); + Optional.ofNullable(toolDTO.getUrl()).ifPresent(tool::setUrl); + Optional.ofNullable(toolDTO.getDescription()).ifPresent(tool::setDescription); + Optional.ofNullable(toolDTO.getEnabled()).ifPresent(tool::setEnabled); + } + + public ToolDTO toDTO(Tool tool) { + return Optional.ofNullable(tool) + .map(t -> { + ToolDTO toolDTO = new ToolDTO(); + toolDTO.setId(t.getId()); + toolDTO.setName(t.getName()); + toolDTO.setUrl(t.getUrl()); + toolDTO.setDescription(t.getDescription()); + Optional.ofNullable(tool.getCreatedBy()) + .map(UserEntity::getId) + .map(permissionManager::getUserById) + .map(UserEntity::getName) + .ifPresent(toolDTO::setCreatedByName); + Optional.ofNullable(tool.getModifiedBy()) + .map(UserEntity::getId) + .map(permissionManager::getUserById) + .map(UserEntity::getName) + .ifPresent(toolDTO::setModifiedByName); + toolDTO.setCreatedDate(DateUtils.dateToString(t.getCreatedDate())); + toolDTO.setModifiedDate(DateUtils.dateToString(t.getModifiedDate())); + toolDTO.setEnabled(t.getEnabled()); + return toolDTO; + }) + .orElse(null); + } +} diff --git a/src/main/java/org/ohdsi/webapi/tool/dto/ToolDTO.java b/src/main/java/org/ohdsi/webapi/tool/dto/ToolDTO.java new file mode 100644 index 0000000000..9a068f6afe --- /dev/null +++ b/src/main/java/org/ohdsi/webapi/tool/dto/ToolDTO.java @@ -0,0 +1,104 @@ +package org.ohdsi.webapi.tool.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.ohdsi.webapi.shiro.Entities.UserEntity; + +import java.util.Objects; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class ToolDTO { + private Integer id; + private String name; + private String url; + private String description; + private String createdByName; + private String modifiedByName; + private String createdDate; + private String modifiedDate; + private Boolean isEnabled; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreatedByName() { + return createdByName; + } + + public void setCreatedByName(String createdByName) { + this.createdByName = createdByName; + } + + public String getModifiedByName() { + return modifiedByName; + } + + public void setModifiedByName(String modifiedByName) { + this.modifiedByName = modifiedByName; + } + + public String getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(String createdDate) { + this.createdDate = createdDate; + } + + public String getModifiedDate() { + return modifiedDate; + } + + public void setModifiedDate(String modifiedDate) { + this.modifiedDate = modifiedDate; + } + + public Boolean getEnabled() { + return isEnabled; + } + + public void setEnabled(Boolean enabled) { + isEnabled = enabled; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ToolDTO toolDTO = (ToolDTO) o; + return Objects.equals(name, toolDTO.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } +} diff --git a/src/main/java/org/ohdsi/webapi/util/DateUtils.java b/src/main/java/org/ohdsi/webapi/util/DateUtils.java new file mode 100644 index 0000000000..2cbffb32eb --- /dev/null +++ b/src/main/java/org/ohdsi/webapi/util/DateUtils.java @@ -0,0 +1,16 @@ +package org.ohdsi.webapi.util; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class DateUtils { + private static final String DATE_FORMAT = "yyyy-MM-dd"; + private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; + + public static String dateToString(Date date) { + if (date == null) return null; + DateFormat df = new SimpleDateFormat(DATE_FORMAT); + return df.format(date); + } +} diff --git a/src/main/resources/db/migration/oracle/V2.8.0.20231205141300__create_table_tools.sql b/src/main/resources/db/migration/oracle/V2.8.0.20231205141300__create_table_tools.sql new file mode 100644 index 0000000000..7f27338829 --- /dev/null +++ b/src/main/resources/db/migration/oracle/V2.8.0.20231205141300__create_table_tools.sql @@ -0,0 +1,35 @@ +CREATE TABLE ${ohdsiSchema}.tool( + id INTEGER NOT NULL, + name VARCHAR(255) NOT NULL, + url VARCHAR(1000) NOT NULL, + description VARCHAR(1000), + created_by_id INTEGER NOT NULL, + modified_by_id INTEGER NOT NULL, + is_enabled bool, + created_date DATE, + modified_date DATE +); + +ALTER TABLE ${ohdsiSchema}.tool ADD ( + CONSTRAINT PK_tool PRIMARY KEY (id)); + +ALTER TABLE ${ohdsiSchema}.tool + ADD CONSTRAINT fk_tool_ser_user_creator FOREIGN KEY (created_by_id) + REFERENCES ${ohdsiSchema}.SEC_USER (id) + ON DELETE CASCADE; + + +ALTER TABLE ${ohdsiSchema}.tool + ADD CONSTRAINT fk_tool_ser_user_updater FOREIGN KEY (modified_by_id) + REFERENCES ${ohdsiSchema}.SEC_USER (id) + ON DELETE CASCADE; + + +CREATE SEQUENCE ${ohdsiSchema}.tool_seq START WITH 1; + +CREATE OR REPLACE TRIGGER ${ohdsiSchema}.tool_bir + BEFORE INSERT ON ${ohdsiSchema}.tool + FOR EACH ROW + BEGIN + SELECT ${ohdsiSchema}.tool_seq.nextval INTO :new.id FROM dual; + END; diff --git a/src/main/resources/db/migration/postgresql/V2.13.1.20231213141052__create_table_tools.sql b/src/main/resources/db/migration/postgresql/V2.13.1.20231213141052__create_table_tools.sql new file mode 100644 index 0000000000..4cf5de02c8 --- /dev/null +++ b/src/main/resources/db/migration/postgresql/V2.13.1.20231213141052__create_table_tools.sql @@ -0,0 +1,18 @@ +CREATE TABLE IF NOT EXISTS ${ohdsiSchema}.tool ( + id BIGINT, + name VARCHAR(255) NOT NULL, + url VARCHAR(1000) NOT NULL, + description VARCHAR(1000), + is_enabled BOOLEAN, + created_by_id INTEGER, + modified_by_id INTEGER, + created_date DATE, + modified_date DATE +); + +ALTER TABLE ${ohdsiSchema}.tool ADD CONSTRAINT PK_tool PRIMARY KEY (id); + +ALTER TABLE ${ohdsiSchema}.tool ADD CONSTRAINT fk_tool_ser_user_creator FOREIGN KEY (created_by_id) REFERENCES ${ohdsiSchema}.sec_user(id); +ALTER TABLE ${ohdsiSchema}.tool ADD CONSTRAINT fk_tool_ser_user_updater FOREIGN KEY (modified_by_id) REFERENCES ${ohdsiSchema}.sec_user(id); + +CREATE SEQUENCE ${ohdsiSchema}.tool_seq START WITH 1 INCREMENT BY 1 MAXVALUE 9223372036854775807 NO CYCLE; \ No newline at end of file diff --git a/src/main/resources/db/migration/sqlserver/V20231213151942__create_table_tools.sql b/src/main/resources/db/migration/sqlserver/V20231213151942__create_table_tools.sql new file mode 100644 index 0000000000..1f2488d323 --- /dev/null +++ b/src/main/resources/db/migration/sqlserver/V20231213151942__create_table_tools.sql @@ -0,0 +1,18 @@ +CREATE TABLE ${ohdsiSchema}.tool ( + id INTEGER PRIMARY KEY, + name VARCHAR (255) NOT NULL, + url VARCHAR (1000) NOT NULL, + description VARCHAR (1000), + is_enabled BIT, + created_by_id INTEGER, + modified_by_id INTEGER, + created_date DATE, + modified_date DATE +); + + +ALTER TABLE ${ohdsiSchema}.tool ADD CONSTRAINT fk_tool_ser_user_creator FOREIGN KEY (created_by_id) REFERENCES ${ohdsiSchema}.sec_user(id); + +ALTER TABLE ${ohdsiSchema}.tool ADD CONSTRAINT fk_tool_ser_user_updater FOREIGN KEY (modified_by_id) REFERENCES ${ohdsiSchema}.sec_user(id); + +CREATE SEQUENCE ${ohdsiSchema}.tool_seq START WITH 1 INCREMENT BY 1 MAXVALUE 9223372036854775807 NO CYCLE; \ No newline at end of file diff --git a/src/main/resources/i18n/messages_en.json b/src/main/resources/i18n/messages_en.json index be9e537c5c..65629e187d 100644 --- a/src/main/resources/i18n/messages_en.json +++ b/src/main/resources/i18n/messages_en.json @@ -116,7 +116,40 @@ "incidenceRate": "Incidence Rate", "ple": "Population Level Effect Estimation", "plp": "Patient Level Prediction", - "reusable": "Reusable" + "reusable": "Reusable", + "addTools": "Add Tool", + "loadingTools": "Loading tools", + "url": "URL", + "apply": "Apply", + "tools": "Tools", + "added": "Added <%=createdDate%>", + "monthsName": { + "january": "January", + "february": "February", + "march": "March", + "april": "April", + "may": "May", + "june": "June", + "july": "July", + "august": "August", + "september": "September", + "october": "October", + "november": "November", + "december": "December" + } + }, + "tool":{ + "name": "* Name", + "url": "* URL", + "nameValidMess": "Tool name cannot be empty.", + "urlValidMess": "Tool url cannot be empty.", + "loading": "Loading tools", + "error": { + "list": "Unable to retrieve the list data at this time; please try again later.", + "create": "Failed to create Tool.", + "update": "Failed to update Tool.", + "delete": "Failed to delete Tool." + } }, "commonErrors": { "noSources": "The current WebAPI has no sources defined.
Please add one or more on configuration page.", @@ -139,7 +172,8 @@ "prediction": "Prediction", "profiles": "Profiles", "search": "Search", - "tagging": "Tagging" + "tagging": "Tagging", + "tools": "Tools" }, "options": { "after": "After", diff --git a/src/main/resources/i18n/messages_ko.json b/src/main/resources/i18n/messages_ko.json index f968018501..29dfafc1f1 100644 --- a/src/main/resources/i18n/messages_ko.json +++ b/src/main/resources/i18n/messages_ko.json @@ -116,7 +116,40 @@ "incidenceRate": "Incidence Rate", "ple": "Population Level Effect Estimation", "plp": "Patient Level Prediction", - "reusable": "Reusable" + "reusable": "Reusable", + "addTools": "도구 추가", + "loadingTools": "도구 로딩", + "url": "URL", + "apply": "적용하다", + "tools": "도구", + "added": "추가됨 <%=createdDate%>", + "monthsName": { + "january": "일월", + "february": "이월", + "march": "삼월", + "april": "사월", + "may": "오월", + "june": "유월", + "july": "칠월", + "august": "팔월", + "september": "구월", + "october": "시월", + "november": "십일월", + "december": "십이월" + } + }, + "tool":{ + "name": "* 이름", + "url": "* URL", + "nameValidMess": "도구 이름은 비워둘 수 없습니다.", + "urlValidMess": "도구 URL은 비워둘 수 없습니다.", + "loading": "도구 로딩", + "error": { + "list": "현재 목록 데이터를 가져올 수 없습니다. 나중에 다시 시도해주세요.", + "create": "도구를 만들지 못했습니다.", + "update": "도구 업데이트에 실패했습니다.", + "delete": "도구 삭제에 실패했습니다." + } }, "commonErrors": { "noSources": "현재 WebAPI에 정의된 소스가 없습니다.
해당 페이지에서 하나 이상을 추가하십시오 configuration page.", @@ -139,7 +172,8 @@ "prediction": "예측", "profiles": "프로필", "search": "검색", - "tagging": "Tagging" + "tagging": "Tagging", + "tools": "도구" }, "options": { "after": "다음", diff --git a/src/main/resources/i18n/messages_ru.json b/src/main/resources/i18n/messages_ru.json index f745819363..f82b11c8b5 100644 --- a/src/main/resources/i18n/messages_ru.json +++ b/src/main/resources/i18n/messages_ru.json @@ -116,7 +116,40 @@ "incidenceRate": "Инцидентность", "ple": "Оценочный анализ", "plp": "Прогнозирование", - "reusable": "Сниппет" + "reusable": "Сниппет", + "addTools": "Добавить инструмент", + "loadingTools": "Загрузка инструментов", + "url": "URL-адрес", + "apply": "Применять", + "tools": "Инструменты", + "added": "Добавлен <%=createdDate%>", + "monthsName": { + "january": "январь", + "february": "февраль", + "march": "Маршировать", + "april": "апрель", + "may": "Может", + "june": "Июнь", + "july": "Июль", + "august": "Август", + "september": "Сентябрь", + "october": "Октябрь", + "november": "ноябрь", + "december": "Декабрь" + } + }, + "tool":{ + "name": "* Имя", + "url": "* URL", + "nameValidMess": "Имя инструмента не может быть пустым.", + "urlValidMess": "URL инструмента не может быть пустым.", + "loading": "Загрузка инструментов", + "error": { + "list": "Невозможно получить список данных в данный момент; попробуйте снова позже.", + "create": "Не удалось создать инструмент.", + "update": "Не удалось обновить инструмент.", + "delete": "Не удалось удалить инструмент." + } }, "commonErrors": { "browserWarning": "Пожалуйста, обратите внимание, что официально поддерживается только браузер Chrome версии не ниже v.63", @@ -139,7 +172,8 @@ "jobs": "Задания", "configuration": "Конфигурация", "feedback": "Обратная связь", - "tagging": "Теггинг" + "tagging": "Теггинг", + "tools": "Инструменты" }, "options": { "atMost": "В большинстве", diff --git a/src/main/resources/i18n/messages_zh.json b/src/main/resources/i18n/messages_zh.json index 29fb81294f..3cf2448b34 100644 --- a/src/main/resources/i18n/messages_zh.json +++ b/src/main/resources/i18n/messages_zh.json @@ -116,7 +116,40 @@ "incidenceRate": "Incidence Rate", "ple": "Population Level Effect Estimation", "plp": "Patient Level Prediction", - "reusable": "Reusable" + "reusable": "Reusable", + "addTools": "添加工具", + "loadingTools": "装载工具", + "url": "网址", + "apply": "申请", + "tools": "工具", + "added": "添加 <%=createdDate%>", + "monthsName": { + "january": "一月", + "february": "二月", + "march": "行进", + "april": "四月", + "may": "可能", + "june": "六月", + "july": "七月", + "august": "八月", + "september": "九月", + "october": "十月", + "november": "十一月", + "december": "十二月" + } + }, + "tool":{ + "name": "* 名称", + "url": "* URL", + "nameValidMess": "工具名称不能为空。", + "urlValidMess": "工具网址不能为空。", + "loading": "装载工具", + "error": { + "list": "当前无法检索列表数据,请稍后重试。", + "create": "创建工具失败。", + "update": "更新工具失败。", + "delete": "删除工具失败。" + } }, "commonErrors": { "noSources": "当前的WebAPI尚未定义源。
请在配置页上添加一个或多个。", @@ -139,7 +172,8 @@ "prediction": "预测", "profiles": "数据概要", "search": "搜索", - "tagging": "Tagging" + "tagging": "Tagging", + "tools": "工具" }, "options": { "after": "在 之后", From 6af331312b660cb482271a58c305527f62c4f3eb Mon Sep 17 00:00:00 2001 From: Juan Carlos Namendi Pineda Date: Thu, 4 Jan 2024 09:28:36 -0600 Subject: [PATCH 02/20] date time update --- src/main/java/org/ohdsi/webapi/util/DateUtils.java | 2 +- .../postgresql/V2.13.1.20231213141052__create_table_tools.sql | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/ohdsi/webapi/util/DateUtils.java b/src/main/java/org/ohdsi/webapi/util/DateUtils.java index 2cbffb32eb..addfb0ce00 100644 --- a/src/main/java/org/ohdsi/webapi/util/DateUtils.java +++ b/src/main/java/org/ohdsi/webapi/util/DateUtils.java @@ -10,7 +10,7 @@ public class DateUtils { public static String dateToString(Date date) { if (date == null) return null; - DateFormat df = new SimpleDateFormat(DATE_FORMAT); + DateFormat df = new SimpleDateFormat(DATE_TIME_FORMAT); return df.format(date); } } diff --git a/src/main/resources/db/migration/postgresql/V2.13.1.20231213141052__create_table_tools.sql b/src/main/resources/db/migration/postgresql/V2.13.1.20231213141052__create_table_tools.sql index 4cf5de02c8..27f01965a2 100644 --- a/src/main/resources/db/migration/postgresql/V2.13.1.20231213141052__create_table_tools.sql +++ b/src/main/resources/db/migration/postgresql/V2.13.1.20231213141052__create_table_tools.sql @@ -6,8 +6,8 @@ CREATE TABLE IF NOT EXISTS ${ohdsiSchema}.tool ( is_enabled BOOLEAN, created_by_id INTEGER, modified_by_id INTEGER, - created_date DATE, - modified_date DATE + created_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT (now()), + modified_date TIMESTAMP WITH TIME ZONE ); ALTER TABLE ${ohdsiSchema}.tool ADD CONSTRAINT PK_tool PRIMARY KEY (id); From 9a5c4b5a3383266dd4d1561d143a74ef1faa2a53 Mon Sep 17 00:00:00 2001 From: Juan Carlos Namendi Pineda Date: Mon, 8 Jan 2024 13:58:36 +0700 Subject: [PATCH 03/20] Update Tools module --- src/main/java/org/ohdsi/webapi/tool/Tool.java | 16 +++++++++++++++- .../org/ohdsi/webapi/tool/ToolController.java | 4 ++-- .../org/ohdsi/webapi/tool/ToolServiceImpl.java | 4 ++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/ohdsi/webapi/tool/Tool.java b/src/main/java/org/ohdsi/webapi/tool/Tool.java index 5da5393aec..eb50d20bac 100644 --- a/src/main/java/org/ohdsi/webapi/tool/Tool.java +++ b/src/main/java/org/ohdsi/webapi/tool/Tool.java @@ -4,7 +4,13 @@ import org.hibernate.annotations.Parameter; import org.ohdsi.webapi.model.CommonEntity; -import javax.persistence.*; +import javax.persistence.Entity; +import javax.persistence.Table; +import javax.persistence.Id; +import javax.persistence.GeneratedValue; +import javax.persistence.Column; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; import java.util.Objects; @Entity @@ -21,8 +27,16 @@ public class Tool extends CommonEntity { ) @GeneratedValue(generator = "tool_generator") private Integer id; + @Size(max = 255) + @NotNull + @Column(name = "name", nullable = false) private String name; + @Size(max = 1000) + @NotNull + @Column(name = "url", nullable = false, length = 1000) private String url; + @Size(max = 1000) + @Column(name = "description", length = 1000) private String description; @Column(name = "is_enabled") private Boolean isEnabled; diff --git a/src/main/java/org/ohdsi/webapi/tool/ToolController.java b/src/main/java/org/ohdsi/webapi/tool/ToolController.java index 362a5bf81a..cfc38ed967 100644 --- a/src/main/java/org/ohdsi/webapi/tool/ToolController.java +++ b/src/main/java/org/ohdsi/webapi/tool/ToolController.java @@ -10,9 +10,9 @@ @Controller @Path("/tool") public class ToolController { - private final ToolService service; + private final ToolServiceImpl service; - public ToolController(ToolService service) { + public ToolController(ToolServiceImpl service) { this.service = service; } diff --git a/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java b/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java index eb42e9aad1..6e04a6acaa 100644 --- a/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java +++ b/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java @@ -40,11 +40,11 @@ public ToolDTO saveTool(ToolDTO toolDTO) { throw new ForbiddenException(); } UserEntity currentUser = permissionManager.getCurrentUser(); - Tool tool = updateToolFromDTO(toolDTO, currentUser); + Tool tool = saveToolFromDTO(toolDTO, currentUser); return toolConvertor.toDTO(toolRepository.saveAndFlush(tool)); } - private Tool updateToolFromDTO(ToolDTO toolDTO, UserEntity currentUser) { + private Tool saveToolFromDTO(ToolDTO toolDTO, UserEntity currentUser) { Tool tool = toolConvertor.toEntity(toolDTO); if (toolDTO.getId() == null) { tool.setCreatedBy(currentUser); From 4f8044b0ae6791ef17eb7e90f0f2dcded3de8805 Mon Sep 17 00:00:00 2001 From: Juan Carlos Namendi Pineda Date: Wed, 31 Jan 2024 10:31:28 +0700 Subject: [PATCH 04/20] Address null exception in case of disabled security --- src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java b/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java index 6e04a6acaa..2cde007b7c 100644 --- a/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java +++ b/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java @@ -3,6 +3,7 @@ import org.ohdsi.webapi.service.AbstractDaoService; import org.ohdsi.webapi.shiro.Entities.UserEntity; import org.ohdsi.webapi.shiro.PermissionManager; +import org.ohdsi.webapi.shiro.management.Security; import org.ohdsi.webapi.tool.converter.ToolConvertor; import org.ohdsi.webapi.tool.dto.ToolDTO; import org.springframework.stereotype.Service; @@ -16,11 +17,13 @@ public class ToolServiceImpl extends AbstractDaoService implements ToolService { private final ToolRepository toolRepository; private final ToolConvertor toolConvertor; private final PermissionManager permissionManager; + private final Security security; - public ToolServiceImpl(ToolRepository toolRepository, ToolConvertor toolConvertor, PermissionManager permissionManager) { + public ToolServiceImpl(ToolRepository toolRepository, ToolConvertor toolConvertor, PermissionManager permissionManager, Security security) { this.toolRepository = toolRepository; this.toolConvertor = toolConvertor; this.permissionManager = permissionManager; + this.security = security; } @Override @@ -36,7 +39,7 @@ public List getTools() { @Override public ToolDTO saveTool(ToolDTO toolDTO) { - if (!isAdmin()) { + if (!isAdmin() || "anonymous".equals(security.getSubject())) { // "anonymous" is the default subject for disabled security throw new ForbiddenException(); } UserEntity currentUser = permissionManager.getCurrentUser(); @@ -60,7 +63,7 @@ public ToolDTO getById(Integer id) { @Override public void delete(Integer id) { - if (isAdmin()) { + if (isAdmin() && !"anonymous".equals(security.getSubject())) { // "anonymous" is the default subject for disabled security toolRepository.delete(id); } else { throw new ForbiddenException(); From e2499b2755bec4921bebd091542733088ccdee49 Mon Sep 17 00:00:00 2001 From: alex-odysseus Date: Wed, 6 Mar 2024 19:47:48 +0100 Subject: [PATCH 05/20] - adding permissions to sec_permission, sec_role_permission (migration script) - distinguishing the Tools listing logic for administrators and the other users - replacing PermissionManager usage with UserRepository when appropriate to avoid exceptions when there is no security enabled --- .../org/ohdsi/webapi/tool/ToolRepository.java | 3 ++ .../ohdsi/webapi/tool/ToolServiceImpl.java | 32 +++++++------------ .../webapi/tool/converter/ToolConvertor.java | 11 ++++--- ...240226195200__tools_module_permissions.sql | 29 +++++++++++++++++ 4 files changed, 50 insertions(+), 25 deletions(-) create mode 100644 src/main/resources/db/migration/postgresql/V2.14.0.20240226195200__tools_module_permissions.sql diff --git a/src/main/java/org/ohdsi/webapi/tool/ToolRepository.java b/src/main/java/org/ohdsi/webapi/tool/ToolRepository.java index ebe624f438..9ed4f36a0f 100644 --- a/src/main/java/org/ohdsi/webapi/tool/ToolRepository.java +++ b/src/main/java/org/ohdsi/webapi/tool/ToolRepository.java @@ -1,8 +1,11 @@ package org.ohdsi.webapi.tool; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface ToolRepository extends JpaRepository { + List findAllByIsEnabled(boolean isEnabled); } diff --git a/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java b/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java index 2cde007b7c..097bed2426 100644 --- a/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java +++ b/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java @@ -1,49 +1,42 @@ package org.ohdsi.webapi.tool; +import java.util.List; +import java.util.stream.Collectors; + +import javax.ws.rs.ForbiddenException; + import org.ohdsi.webapi.service.AbstractDaoService; import org.ohdsi.webapi.shiro.Entities.UserEntity; -import org.ohdsi.webapi.shiro.PermissionManager; -import org.ohdsi.webapi.shiro.management.Security; import org.ohdsi.webapi.tool.converter.ToolConvertor; import org.ohdsi.webapi.tool.dto.ToolDTO; import org.springframework.stereotype.Service; -import javax.ws.rs.ForbiddenException; -import java.util.List; -import java.util.stream.Collectors; - @Service public class ToolServiceImpl extends AbstractDaoService implements ToolService { private final ToolRepository toolRepository; private final ToolConvertor toolConvertor; - private final PermissionManager permissionManager; - private final Security security; - public ToolServiceImpl(ToolRepository toolRepository, ToolConvertor toolConvertor, PermissionManager permissionManager, Security security) { + public ToolServiceImpl(ToolRepository toolRepository, ToolConvertor toolConvertor) { this.toolRepository = toolRepository; this.toolConvertor = toolConvertor; - this.permissionManager = permissionManager; - this.security = security; } @Override public List getTools() { - return toolRepository.findAll().stream() + List tools = isAdmin() ? toolRepository.findAll() : toolRepository.findAllByIsEnabled(true); + return tools.stream() .map(tool -> { ToolDTO dto = toolConvertor.toDTO(tool); - UserEntity userById = permissionManager.getUserById(tool.getCreatedBy().getId()); - dto.setCreatedByName(userById.getName()); return dto; }).collect(Collectors.toList()); } @Override public ToolDTO saveTool(ToolDTO toolDTO) { - if (!isAdmin() || "anonymous".equals(security.getSubject())) { // "anonymous" is the default subject for disabled security + if (!isAdmin()) { throw new ForbiddenException(); } - UserEntity currentUser = permissionManager.getCurrentUser(); - Tool tool = saveToolFromDTO(toolDTO, currentUser); + Tool tool = saveToolFromDTO(toolDTO, getCurrentUser()); return toolConvertor.toDTO(toolRepository.saveAndFlush(tool)); } @@ -63,10 +56,9 @@ public ToolDTO getById(Integer id) { @Override public void delete(Integer id) { - if (isAdmin() && !"anonymous".equals(security.getSubject())) { // "anonymous" is the default subject for disabled security - toolRepository.delete(id); - } else { + if (!isAdmin()) { throw new ForbiddenException(); } + toolRepository.delete(id); } } \ No newline at end of file diff --git a/src/main/java/org/ohdsi/webapi/tool/converter/ToolConvertor.java b/src/main/java/org/ohdsi/webapi/tool/converter/ToolConvertor.java index 6fd9b452b2..3b31f6144e 100644 --- a/src/main/java/org/ohdsi/webapi/tool/converter/ToolConvertor.java +++ b/src/main/java/org/ohdsi/webapi/tool/converter/ToolConvertor.java @@ -2,6 +2,7 @@ import org.ohdsi.webapi.service.AbstractDaoService; import org.ohdsi.webapi.shiro.Entities.UserEntity; +import org.ohdsi.webapi.shiro.Entities.UserRepository; import org.ohdsi.webapi.shiro.PermissionManager; import org.ohdsi.webapi.tool.Tool; import org.ohdsi.webapi.tool.ToolRepository; @@ -16,11 +17,11 @@ @Component public class ToolConvertor extends AbstractDaoService { private final ToolRepository toolRepository; - private final PermissionManager permissionManager; + private final UserRepository userRepository; - public ToolConvertor(ToolRepository toolRepository, PermissionManager permissionManager) { + public ToolConvertor(ToolRepository toolRepository, UserRepository userRepository) { this.toolRepository = toolRepository; - this.permissionManager = permissionManager; + this.userRepository = userRepository; } public Tool toEntity(ToolDTO toolDTO) { @@ -63,12 +64,12 @@ public ToolDTO toDTO(Tool tool) { toolDTO.setDescription(t.getDescription()); Optional.ofNullable(tool.getCreatedBy()) .map(UserEntity::getId) - .map(permissionManager::getUserById) + .map(userRepository::findOne) .map(UserEntity::getName) .ifPresent(toolDTO::setCreatedByName); Optional.ofNullable(tool.getModifiedBy()) .map(UserEntity::getId) - .map(permissionManager::getUserById) + .map(userRepository::findOne) .map(UserEntity::getName) .ifPresent(toolDTO::setModifiedByName); toolDTO.setCreatedDate(DateUtils.dateToString(t.getCreatedDate())); diff --git a/src/main/resources/db/migration/postgresql/V2.14.0.20240226195200__tools_module_permissions.sql b/src/main/resources/db/migration/postgresql/V2.14.0.20240226195200__tools_module_permissions.sql new file mode 100644 index 0000000000..12c2fe0966 --- /dev/null +++ b/src/main/resources/db/migration/postgresql/V2.14.0.20240226195200__tools_module_permissions.sql @@ -0,0 +1,29 @@ +INSERT INTO ${ohdsiSchema}.sec_permission(id, value, description) VALUES + (nextval('${ohdsiSchema}.sec_permission_id_seq'), 'tool:post', 'Create Tool'); +INSERT INTO ${ohdsiSchema}.sec_permission(id, value, description) VALUES + (nextval('${ohdsiSchema}.sec_permission_id_seq'), 'tool:put', 'Update Tool'); +INSERT INTO ${ohdsiSchema}.sec_permission(id, value, description) VALUES + (nextval('${ohdsiSchema}.sec_permission_id_seq'), 'tool:get', 'List Tools'); +INSERT INTO ${ohdsiSchema}.sec_permission(id, value, description) VALUES + (nextval('${ohdsiSchema}.sec_permission_id_seq'), 'tool:*:get', 'View Tool'); +INSERT INTO ${ohdsiSchema}.sec_permission(id, value, description) VALUES + (nextval('${ohdsiSchema}.sec_permission_id_seq'), 'tool:*:delete', 'View Tool'); + +INSERT INTO ${ohdsiSchema}.sec_role_permission(id, role_id, permission_id) +SELECT nextval('${ohdsiSchema}.sec_role_permission_sequence'), sr.id, sp.id +FROM ${ohdsiSchema}.sec_permission SP, ${ohdsiSchema}.sec_role sr +WHERE sp.value IN ( + 'tool:post', + 'tool:put', + 'tool:get', + 'tool:*:get', + 'tool:*:delete' + ) AND sr.name IN ('admin'); + +INSERT INTO ${ohdsiSchema}.sec_role_permission(id, role_id, permission_id) +SELECT nextval('${ohdsiSchema}.sec_role_permission_sequence'), sr.id, sp.id +FROM ${ohdsiSchema}.sec_permission SP, ${ohdsiSchema}.sec_role sr +WHERE sp.value IN ( + 'tool:get', + 'tool:*:get' + ) AND sr.name IN ('Atlas users'); \ No newline at end of file From 024384b590ce6b3e9b59ef17199fac9704a9ada6 Mon Sep 17 00:00:00 2001 From: Juan Carlos Namendi Pineda Date: Thu, 7 Mar 2024 17:28:48 +0700 Subject: [PATCH 06/20] Remove validation from the Tool class. --- src/main/java/org/ohdsi/webapi/tool/Tool.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/ohdsi/webapi/tool/Tool.java b/src/main/java/org/ohdsi/webapi/tool/Tool.java index eb50d20bac..123b9be16e 100644 --- a/src/main/java/org/ohdsi/webapi/tool/Tool.java +++ b/src/main/java/org/ohdsi/webapi/tool/Tool.java @@ -27,16 +27,14 @@ public class Tool extends CommonEntity { ) @GeneratedValue(generator = "tool_generator") private Integer id; - @Size(max = 255) - @NotNull - @Column(name = "name", nullable = false) + + @Column(name = "name") private String name; - @Size(max = 1000) - @NotNull - @Column(name = "url", nullable = false, length = 1000) + + @Column(name = "url") private String url; - @Size(max = 1000) - @Column(name = "description", length = 1000) + + @Column(name = "description") private String description; @Column(name = "is_enabled") private Boolean isEnabled; From 36555aaa7d9ce2c6c5a26ae7b3604826cee35117 Mon Sep 17 00:00:00 2001 From: Juan Carlos Namendi Pineda Date: Thu, 7 Mar 2024 17:31:44 +0700 Subject: [PATCH 07/20] Remove validation from the Tool class. --- src/main/java/org/ohdsi/webapi/tool/Tool.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/ohdsi/webapi/tool/Tool.java b/src/main/java/org/ohdsi/webapi/tool/Tool.java index 123b9be16e..46f6385de7 100644 --- a/src/main/java/org/ohdsi/webapi/tool/Tool.java +++ b/src/main/java/org/ohdsi/webapi/tool/Tool.java @@ -9,8 +9,6 @@ import javax.persistence.Id; import javax.persistence.GeneratedValue; import javax.persistence.Column; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; import java.util.Objects; @Entity From 3bb1bfe4f4f421e96f6b0087699dbe17935b756b Mon Sep 17 00:00:00 2001 From: Juan Carlos Namendi Pineda Date: Wed, 3 Apr 2024 16:52:56 +0700 Subject: [PATCH 08/20] Add tool permission --- .../webapi/security/model/EntityType.java | 2 ++ .../security/model/ToolPermissionSchema.java | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java diff --git a/src/main/java/org/ohdsi/webapi/security/model/EntityType.java b/src/main/java/org/ohdsi/webapi/security/model/EntityType.java index d5a9d63acf..8c800cdedd 100644 --- a/src/main/java/org/ohdsi/webapi/security/model/EntityType.java +++ b/src/main/java/org/ohdsi/webapi/security/model/EntityType.java @@ -13,6 +13,7 @@ import org.ohdsi.webapi.reusable.domain.Reusable; import org.ohdsi.webapi.source.Source; import org.ohdsi.webapi.tag.domain.Tag; +import org.ohdsi.webapi.tool.Tool; public enum EntityType { COHORT_DEFINITION(CohortDefinition.class), @@ -26,6 +27,7 @@ public enum EntityType { PREDICTION(PredictionAnalysis.class), COHORT_SAMPLE(CohortSample.class), TAG(Tag.class), + TOOL(Tool.class), REUSABLE(Reusable.class); private final Class entityClass; diff --git a/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java b/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java new file mode 100644 index 0000000000..5d8bc8485b --- /dev/null +++ b/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java @@ -0,0 +1,20 @@ +package org.ohdsi.webapi.security.model; +import org.springframework.stereotype.Component; +import java.util.HashMap; +import java.util.Map; +@Component +public class ToolPermissionSchema extends EntityPermissionSchema { + private static Map writePermissions = new HashMap() {{ + put("tool:*:delete", "Delete tool"); + put("tool:*:put", "Update tool"); + put("tool:*:post", "Edit tool"); + }}; + private static Map readPermissions = new HashMap() {{ + put("tool:get", "view tool with id %s"); + put("tool:*:get", "Resolve tool %s expression"); + } + }; + public ToolPermissionSchema() { + super(EntityType.TOOL, new HashMap<>(), writePermissions); + } +} \ No newline at end of file From 498b4c9c40855413455693761e17d088ec19e34d Mon Sep 17 00:00:00 2001 From: Juan Carlos Namendi Pineda Date: Thu, 11 Apr 2024 16:59:55 +0700 Subject: [PATCH 09/20] add tools messages i18n --- src/main/resources/i18n/messages_en.json | 4 +++- src/main/resources/i18n/messages_ko.json | 4 +++- src/main/resources/i18n/messages_ru.json | 4 +++- src/main/resources/i18n/messages_zh.json | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/resources/i18n/messages_en.json b/src/main/resources/i18n/messages_en.json index 65629e187d..5bc8892a3a 100644 --- a/src/main/resources/i18n/messages_en.json +++ b/src/main/resources/i18n/messages_en.json @@ -149,7 +149,9 @@ "create": "Failed to create Tool.", "update": "Failed to update Tool.", "delete": "Failed to delete Tool." - } + }, + "toolDisabled": "Tool disabled", + "toolEnabled": "Tool enabled" }, "commonErrors": { "noSources": "The current WebAPI has no sources defined.
Please add one or more on configuration page.", diff --git a/src/main/resources/i18n/messages_ko.json b/src/main/resources/i18n/messages_ko.json index 29dfafc1f1..dfbc813866 100644 --- a/src/main/resources/i18n/messages_ko.json +++ b/src/main/resources/i18n/messages_ko.json @@ -149,7 +149,9 @@ "create": "도구를 만들지 못했습니다.", "update": "도구 업데이트에 실패했습니다.", "delete": "도구 삭제에 실패했습니다." - } + }, + "toolDisabled": "도구 비활성화됨", + "toolEnabled": "도구 활성화됨" }, "commonErrors": { "noSources": "현재 WebAPI에 정의된 소스가 없습니다.
해당 페이지에서 하나 이상을 추가하십시오 configuration page.", diff --git a/src/main/resources/i18n/messages_ru.json b/src/main/resources/i18n/messages_ru.json index f82b11c8b5..0760b032be 100644 --- a/src/main/resources/i18n/messages_ru.json +++ b/src/main/resources/i18n/messages_ru.json @@ -149,7 +149,9 @@ "create": "Не удалось создать инструмент.", "update": "Не удалось обновить инструмент.", "delete": "Не удалось удалить инструмент." - } + }, + "toolDisabled": "Инструмент отключен", + "toolEnabled": "Инструмент включен" }, "commonErrors": { "browserWarning": "Пожалуйста, обратите внимание, что официально поддерживается только браузер Chrome версии не ниже v.63", diff --git a/src/main/resources/i18n/messages_zh.json b/src/main/resources/i18n/messages_zh.json index 3cf2448b34..83a7f1c923 100644 --- a/src/main/resources/i18n/messages_zh.json +++ b/src/main/resources/i18n/messages_zh.json @@ -149,7 +149,9 @@ "create": "创建工具失败。", "update": "更新工具失败。", "delete": "删除工具失败。" - } + }, + "toolDisabled":"工具已禁用", + "toolEnabled": "工具已启用" }, "commonErrors": { "noSources": "当前的WebAPI尚未定义源。
请在配置页上添加一个或多个。", From 132c1c7df27eb26f54b86d6736946f02287f304a Mon Sep 17 00:00:00 2001 From: Juan Carlos Namendi Pineda Date: Thu, 18 Apr 2024 15:04:23 +0700 Subject: [PATCH 10/20] Fixed deleting a record would delete the role --- .../security/model/ToolPermissionSchema.java | 24 ++++++++++++------- ...240226195200__tools_module_permissions.sql | 2 +- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java b/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java index 5d8bc8485b..aa6b388cd1 100644 --- a/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java +++ b/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java @@ -1,20 +1,28 @@ package org.ohdsi.webapi.security.model; + +import org.ohdsi.webapi.model.CommonEntity; +import org.ohdsi.webapi.shiro.Entities.RoleEntity; +import org.ohdsi.webapi.tool.Tool; import org.springframework.stereotype.Component; + import java.util.HashMap; import java.util.Map; + @Component public class ToolPermissionSchema extends EntityPermissionSchema { private static Map writePermissions = new HashMap() {{ - put("tool:*:delete", "Delete tool"); - put("tool:*:put", "Update tool"); - put("tool:*:post", "Edit tool"); + put("tool:%s:delete", "Delete Tool with by id = %s"); + put("tool:%s:put", "Update Tool with by id = %s"); + put("tool:%s:post", "Create Tool with by id = %s"); }}; - private static Map readPermissions = new HashMap() {{ - put("tool:get", "view tool with id %s"); - put("tool:*:get", "Resolve tool %s expression"); - } + private static Map readPermissions = new HashMap() { + { + put("tool:%s:get", "View Tool with by id = %s"); + } }; + public ToolPermissionSchema() { - super(EntityType.TOOL, new HashMap<>(), writePermissions); + super(EntityType.TOOL, readPermissions, writePermissions); } + } \ No newline at end of file diff --git a/src/main/resources/db/migration/postgresql/V2.14.0.20240226195200__tools_module_permissions.sql b/src/main/resources/db/migration/postgresql/V2.14.0.20240226195200__tools_module_permissions.sql index 12c2fe0966..ecd44ce809 100644 --- a/src/main/resources/db/migration/postgresql/V2.14.0.20240226195200__tools_module_permissions.sql +++ b/src/main/resources/db/migration/postgresql/V2.14.0.20240226195200__tools_module_permissions.sql @@ -7,7 +7,7 @@ INSERT INTO ${ohdsiSchema}.sec_permission(id, value, description) VALUES INSERT INTO ${ohdsiSchema}.sec_permission(id, value, description) VALUES (nextval('${ohdsiSchema}.sec_permission_id_seq'), 'tool:*:get', 'View Tool'); INSERT INTO ${ohdsiSchema}.sec_permission(id, value, description) VALUES - (nextval('${ohdsiSchema}.sec_permission_id_seq'), 'tool:*:delete', 'View Tool'); + (nextval('${ohdsiSchema}.sec_permission_id_seq'), 'tool:*:delete', 'Delete Tool'); INSERT INTO ${ohdsiSchema}.sec_role_permission(id, role_id, permission_id) SELECT nextval('${ohdsiSchema}.sec_role_permission_sequence'), sr.id, sp.id From 389fac5207be756881c204712b3bba94fb3da138 Mon Sep 17 00:00:00 2001 From: Juan Carlos Namendi Pineda Date: Thu, 18 Apr 2024 05:55:15 -0600 Subject: [PATCH 11/20] Remove unused imports --- .../webapi/security/model/ToolPermissionSchema.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java b/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java index aa6b388cd1..99ff7f7e37 100644 --- a/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java +++ b/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java @@ -1,8 +1,5 @@ package org.ohdsi.webapi.security.model; -import org.ohdsi.webapi.model.CommonEntity; -import org.ohdsi.webapi.shiro.Entities.RoleEntity; -import org.ohdsi.webapi.tool.Tool; import org.springframework.stereotype.Component; import java.util.HashMap; @@ -11,13 +8,13 @@ @Component public class ToolPermissionSchema extends EntityPermissionSchema { private static Map writePermissions = new HashMap() {{ - put("tool:%s:delete", "Delete Tool with by id = %s"); - put("tool:%s:put", "Update Tool with by id = %s"); - put("tool:%s:post", "Create Tool with by id = %s"); + put("tool:%s:delete", "Delete Tool with id = %s"); + put("tool:%s:put", "Update Tool with id = %s"); + put("tool:%s:post", "Create Tool with id = %s"); }}; private static Map readPermissions = new HashMap() { { - put("tool:%s:get", "View Tool with by id = %s"); + put("tool:%s:get", "View Tool with id = %s"); } }; From a49ceabe6c28056ed8813bdeef08d05fc8bb422a Mon Sep 17 00:00:00 2001 From: Juan Carlos Namendi Pineda Date: Mon, 6 May 2024 10:38:32 -0600 Subject: [PATCH 12/20] Check if the delete permission for tools is present to add it back. --- ...dd_delete_tool_permission_if_not_exists.sql | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/main/resources/db/migration/postgresql/V2.14.0.20240506100635__add_delete_tool_permission_if_not_exists.sql diff --git a/src/main/resources/db/migration/postgresql/V2.14.0.20240506100635__add_delete_tool_permission_if_not_exists.sql b/src/main/resources/db/migration/postgresql/V2.14.0.20240506100635__add_delete_tool_permission_if_not_exists.sql new file mode 100644 index 0000000000..32480b5009 --- /dev/null +++ b/src/main/resources/db/migration/postgresql/V2.14.0.20240506100635__add_delete_tool_permission_if_not_exists.sql @@ -0,0 +1,18 @@ +INSERT INTO ${ohdsiSchema}.sec_permission (id, value, description) +SELECT nextval('${ohdsiSchema}.sec_permission_id_seq'), 'tool:*:delete', 'Delete Tool' +WHERE NOT EXISTS ( + SELECT NULL FROM ${ohdsiSchema}.sec_permission + WHERE value = 'tool:*:delete' +); + +INSERT INTO ${ohdsiSchema}.sec_role_permission(id, role_id, permission_id) +SELECT nextval('${ohdsiSchema}.sec_role_permission_sequence'), sr.id, sp.id +FROM ${ohdsiSchema}.sec_permission SP, ${ohdsiSchema}.sec_role sr +WHERE sp.value IN ( + 'tool:*:delete' + ) AND sr.name IN ('admin') + AND NOT EXISTS ( + SELECT NULL FROM ${ohdsiSchema}.sec_role_permission + WHERE permission_id = sp.id and role_id = sr.id); + + From 88b51dddf37455e59c80e4b417dbf4f3ccde8185 Mon Sep 17 00:00:00 2001 From: alex-odysseus Date: Fri, 30 Aug 2024 14:05:40 +0200 Subject: [PATCH 13/20] Oracle and Microsoft SQL migrations should be no longer supported --- ...8.0.20231205141300__create_table_tools.sql | 35 ------------------- .../V20231213151942__create_table_tools.sql | 18 ---------- 2 files changed, 53 deletions(-) delete mode 100644 src/main/resources/db/migration/oracle/V2.8.0.20231205141300__create_table_tools.sql delete mode 100644 src/main/resources/db/migration/sqlserver/V20231213151942__create_table_tools.sql diff --git a/src/main/resources/db/migration/oracle/V2.8.0.20231205141300__create_table_tools.sql b/src/main/resources/db/migration/oracle/V2.8.0.20231205141300__create_table_tools.sql deleted file mode 100644 index 7f27338829..0000000000 --- a/src/main/resources/db/migration/oracle/V2.8.0.20231205141300__create_table_tools.sql +++ /dev/null @@ -1,35 +0,0 @@ -CREATE TABLE ${ohdsiSchema}.tool( - id INTEGER NOT NULL, - name VARCHAR(255) NOT NULL, - url VARCHAR(1000) NOT NULL, - description VARCHAR(1000), - created_by_id INTEGER NOT NULL, - modified_by_id INTEGER NOT NULL, - is_enabled bool, - created_date DATE, - modified_date DATE -); - -ALTER TABLE ${ohdsiSchema}.tool ADD ( - CONSTRAINT PK_tool PRIMARY KEY (id)); - -ALTER TABLE ${ohdsiSchema}.tool - ADD CONSTRAINT fk_tool_ser_user_creator FOREIGN KEY (created_by_id) - REFERENCES ${ohdsiSchema}.SEC_USER (id) - ON DELETE CASCADE; - - -ALTER TABLE ${ohdsiSchema}.tool - ADD CONSTRAINT fk_tool_ser_user_updater FOREIGN KEY (modified_by_id) - REFERENCES ${ohdsiSchema}.SEC_USER (id) - ON DELETE CASCADE; - - -CREATE SEQUENCE ${ohdsiSchema}.tool_seq START WITH 1; - -CREATE OR REPLACE TRIGGER ${ohdsiSchema}.tool_bir - BEFORE INSERT ON ${ohdsiSchema}.tool - FOR EACH ROW - BEGIN - SELECT ${ohdsiSchema}.tool_seq.nextval INTO :new.id FROM dual; - END; diff --git a/src/main/resources/db/migration/sqlserver/V20231213151942__create_table_tools.sql b/src/main/resources/db/migration/sqlserver/V20231213151942__create_table_tools.sql deleted file mode 100644 index 1f2488d323..0000000000 --- a/src/main/resources/db/migration/sqlserver/V20231213151942__create_table_tools.sql +++ /dev/null @@ -1,18 +0,0 @@ -CREATE TABLE ${ohdsiSchema}.tool ( - id INTEGER PRIMARY KEY, - name VARCHAR (255) NOT NULL, - url VARCHAR (1000) NOT NULL, - description VARCHAR (1000), - is_enabled BIT, - created_by_id INTEGER, - modified_by_id INTEGER, - created_date DATE, - modified_date DATE -); - - -ALTER TABLE ${ohdsiSchema}.tool ADD CONSTRAINT fk_tool_ser_user_creator FOREIGN KEY (created_by_id) REFERENCES ${ohdsiSchema}.sec_user(id); - -ALTER TABLE ${ohdsiSchema}.tool ADD CONSTRAINT fk_tool_ser_user_updater FOREIGN KEY (modified_by_id) REFERENCES ${ohdsiSchema}.sec_user(id); - -CREATE SEQUENCE ${ohdsiSchema}.tool_seq START WITH 1 INCREMENT BY 1 MAXVALUE 9223372036854775807 NO CYCLE; \ No newline at end of file From 2cfa1a1c88f24ddff08dec182cca99851314c150 Mon Sep 17 00:00:00 2001 From: alex-odysseus Date: Fri, 30 Aug 2024 14:24:03 +0200 Subject: [PATCH 14/20] Removing unused translations --- src/main/resources/i18n/messages_en.json | 18 +----------------- src/main/resources/i18n/messages_ko.json | 18 +----------------- src/main/resources/i18n/messages_ru.json | 18 +----------------- src/main/resources/i18n/messages_zh.json | 18 +----------------- 4 files changed, 4 insertions(+), 68 deletions(-) diff --git a/src/main/resources/i18n/messages_en.json b/src/main/resources/i18n/messages_en.json index 5bc8892a3a..2c8ba8d503 100644 --- a/src/main/resources/i18n/messages_en.json +++ b/src/main/resources/i18n/messages_en.json @@ -118,25 +118,9 @@ "plp": "Patient Level Prediction", "reusable": "Reusable", "addTools": "Add Tool", - "loadingTools": "Loading tools", "url": "URL", "apply": "Apply", - "tools": "Tools", - "added": "Added <%=createdDate%>", - "monthsName": { - "january": "January", - "february": "February", - "march": "March", - "april": "April", - "may": "May", - "june": "June", - "july": "July", - "august": "August", - "september": "September", - "october": "October", - "november": "November", - "december": "December" - } + "tools": "Tools" }, "tool":{ "name": "* Name", diff --git a/src/main/resources/i18n/messages_ko.json b/src/main/resources/i18n/messages_ko.json index dfbc813866..871bf6611d 100644 --- a/src/main/resources/i18n/messages_ko.json +++ b/src/main/resources/i18n/messages_ko.json @@ -118,25 +118,9 @@ "plp": "Patient Level Prediction", "reusable": "Reusable", "addTools": "도구 추가", - "loadingTools": "도구 로딩", "url": "URL", "apply": "적용하다", - "tools": "도구", - "added": "추가됨 <%=createdDate%>", - "monthsName": { - "january": "일월", - "february": "이월", - "march": "삼월", - "april": "사월", - "may": "오월", - "june": "유월", - "july": "칠월", - "august": "팔월", - "september": "구월", - "october": "시월", - "november": "십일월", - "december": "십이월" - } + "tools": "도구" }, "tool":{ "name": "* 이름", diff --git a/src/main/resources/i18n/messages_ru.json b/src/main/resources/i18n/messages_ru.json index 0760b032be..4b89045132 100644 --- a/src/main/resources/i18n/messages_ru.json +++ b/src/main/resources/i18n/messages_ru.json @@ -118,25 +118,9 @@ "plp": "Прогнозирование", "reusable": "Сниппет", "addTools": "Добавить инструмент", - "loadingTools": "Загрузка инструментов", "url": "URL-адрес", "apply": "Применять", - "tools": "Инструменты", - "added": "Добавлен <%=createdDate%>", - "monthsName": { - "january": "январь", - "february": "февраль", - "march": "Маршировать", - "april": "апрель", - "may": "Может", - "june": "Июнь", - "july": "Июль", - "august": "Август", - "september": "Сентябрь", - "october": "Октябрь", - "november": "ноябрь", - "december": "Декабрь" - } + "tools": "Инструменты" }, "tool":{ "name": "* Имя", diff --git a/src/main/resources/i18n/messages_zh.json b/src/main/resources/i18n/messages_zh.json index 83a7f1c923..a600694d67 100644 --- a/src/main/resources/i18n/messages_zh.json +++ b/src/main/resources/i18n/messages_zh.json @@ -118,25 +118,9 @@ "plp": "Patient Level Prediction", "reusable": "Reusable", "addTools": "添加工具", - "loadingTools": "装载工具", "url": "网址", "apply": "申请", - "tools": "工具", - "added": "添加 <%=createdDate%>", - "monthsName": { - "january": "一月", - "february": "二月", - "march": "行进", - "april": "四月", - "may": "可能", - "june": "六月", - "july": "七月", - "august": "八月", - "september": "九月", - "october": "十月", - "november": "十一月", - "december": "十二月" - } + "tools": "工具" }, "tool":{ "name": "* 名称", From 5acc1268974e3595bd1db8705f1117ce529ddf92 Mon Sep 17 00:00:00 2001 From: oleg-odysseus Date: Fri, 25 Oct 2024 19:46:56 +0200 Subject: [PATCH 15/20] Fixed issue where non-administrator tool editor was unable to save entities --- .../org/ohdsi/webapi/tool/ToolServiceImpl.java | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java b/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java index 097bed2426..bf9b60bfcc 100644 --- a/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java +++ b/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java @@ -2,9 +2,6 @@ import java.util.List; import java.util.stream.Collectors; - -import javax.ws.rs.ForbiddenException; - import org.ohdsi.webapi.service.AbstractDaoService; import org.ohdsi.webapi.shiro.Entities.UserEntity; import org.ohdsi.webapi.tool.converter.ToolConvertor; @@ -25,17 +22,11 @@ public ToolServiceImpl(ToolRepository toolRepository, ToolConvertor toolConverto public List getTools() { List tools = isAdmin() ? toolRepository.findAll() : toolRepository.findAllByIsEnabled(true); return tools.stream() - .map(tool -> { - ToolDTO dto = toolConvertor.toDTO(tool); - return dto; - }).collect(Collectors.toList()); + .map(toolConvertor::toDTO).collect(Collectors.toList()); } @Override public ToolDTO saveTool(ToolDTO toolDTO) { - if (!isAdmin()) { - throw new ForbiddenException(); - } Tool tool = saveToolFromDTO(toolDTO, getCurrentUser()); return toolConvertor.toDTO(toolRepository.saveAndFlush(tool)); } @@ -56,9 +47,6 @@ public ToolDTO getById(Integer id) { @Override public void delete(Integer id) { - if (!isAdmin()) { - throw new ForbiddenException(); - } toolRepository.delete(id); } } \ No newline at end of file From a6d527429b4dd52dd06b585dbfff465c9e8e7610 Mon Sep 17 00:00:00 2001 From: oleg-odysseus Date: Fri, 1 Nov 2024 16:37:22 +0100 Subject: [PATCH 16/20] Allowed reading non-enabled tools by a user having 'tool:post && tool:put && tool:*:delete' permissions --- .../java/org/ohdsi/webapi/tool/ToolServiceImpl.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java b/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java index bf9b60bfcc..f68d87b969 100644 --- a/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java +++ b/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java @@ -2,6 +2,9 @@ import java.util.List; import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.shiro.SecurityUtils; import org.ohdsi.webapi.service.AbstractDaoService; import org.ohdsi.webapi.shiro.Entities.UserEntity; import org.ohdsi.webapi.tool.converter.ToolConvertor; @@ -20,7 +23,7 @@ public ToolServiceImpl(ToolRepository toolRepository, ToolConvertor toolConverto @Override public List getTools() { - List tools = isAdmin() ? toolRepository.findAll() : toolRepository.findAllByIsEnabled(true); + List tools = (isAdmin() || canManageTools()) ? toolRepository.findAll() : toolRepository.findAllByIsEnabled(true); return tools.stream() .map(toolConvertor::toDTO).collect(Collectors.toList()); } @@ -49,4 +52,9 @@ public ToolDTO getById(Integer id) { public void delete(Integer id) { toolRepository.delete(id); } + + private boolean canManageTools() { + return Stream.of("tool:put", "tool:post", "tool:*:delete") + .allMatch(permission -> SecurityUtils.getSubject().isPermitted(permission)); + } } \ No newline at end of file From 1e36b5c6cc8c94a33c634775395d18b27fdf06ee Mon Sep 17 00:00:00 2001 From: alex-odysseus Date: Tue, 17 Dec 2024 12:28:55 +0100 Subject: [PATCH 17/20] Combining migration scripts into one, removing redundant classes, minor renaming and imports notation --- src/main/java/org/ohdsi/webapi/tool/Tool.java | 6 +- .../org/ohdsi/webapi/tool/ToolController.java | 9 +- .../ohdsi/webapi/tool/ToolServiceImpl.java | 76 +++++++++++++++-- .../webapi/tool/converter/ToolConvertor.java | 82 ------------------- .../java/org/ohdsi/webapi/util/DateUtils.java | 16 ---- ...3.1.20231213141052__create_table_tools.sql | 18 ---- ...d_delete_tool_permission_if_not_exists.sql | 18 ---- ...2__create_table_tools_and_permissions.sql} | 21 ++++- 8 files changed, 99 insertions(+), 147 deletions(-) delete mode 100644 src/main/java/org/ohdsi/webapi/tool/converter/ToolConvertor.java delete mode 100644 src/main/java/org/ohdsi/webapi/util/DateUtils.java delete mode 100644 src/main/resources/db/migration/postgresql/V2.13.1.20231213141052__create_table_tools.sql delete mode 100644 src/main/resources/db/migration/postgresql/V2.14.0.20240506100635__add_delete_tool_permission_if_not_exists.sql rename src/main/resources/db/migration/postgresql/{V2.14.0.20240226195200__tools_module_permissions.sql => V2.15.0.20231213141052__create_table_tools_and_permissions.sql} (62%) diff --git a/src/main/java/org/ohdsi/webapi/tool/Tool.java b/src/main/java/org/ohdsi/webapi/tool/Tool.java index 46f6385de7..93f9d31350 100644 --- a/src/main/java/org/ohdsi/webapi/tool/Tool.java +++ b/src/main/java/org/ohdsi/webapi/tool/Tool.java @@ -35,7 +35,7 @@ public class Tool extends CommonEntity { @Column(name = "description") private String description; @Column(name = "is_enabled") - private Boolean isEnabled; + private Boolean enabled; @Override public Integer getId() { @@ -71,11 +71,11 @@ public void setDescription(String description) { } public Boolean getEnabled() { - return isEnabled; + return enabled; } public void setEnabled(Boolean enabled) { - isEnabled = enabled; + this.enabled = enabled; } @Override diff --git a/src/main/java/org/ohdsi/webapi/tool/ToolController.java b/src/main/java/org/ohdsi/webapi/tool/ToolController.java index cfc38ed967..2b593076c2 100644 --- a/src/main/java/org/ohdsi/webapi/tool/ToolController.java +++ b/src/main/java/org/ohdsi/webapi/tool/ToolController.java @@ -3,7 +3,14 @@ import org.ohdsi.webapi.tool.dto.ToolDTO; import org.springframework.stereotype.Controller; -import javax.ws.rs.*; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import java.util.List; diff --git a/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java b/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java index f68d87b969..3dc17dd3b1 100644 --- a/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java +++ b/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java @@ -1,41 +1,44 @@ package org.ohdsi.webapi.tool; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.util.Date; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.shiro.SecurityUtils; import org.ohdsi.webapi.service.AbstractDaoService; import org.ohdsi.webapi.shiro.Entities.UserEntity; -import org.ohdsi.webapi.tool.converter.ToolConvertor; import org.ohdsi.webapi.tool.dto.ToolDTO; import org.springframework.stereotype.Service; @Service public class ToolServiceImpl extends AbstractDaoService implements ToolService { + private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; + private final ToolRepository toolRepository; - private final ToolConvertor toolConvertor; - public ToolServiceImpl(ToolRepository toolRepository, ToolConvertor toolConvertor) { + public ToolServiceImpl(ToolRepository toolRepository) { this.toolRepository = toolRepository; - this.toolConvertor = toolConvertor; } @Override public List getTools() { List tools = (isAdmin() || canManageTools()) ? toolRepository.findAll() : toolRepository.findAllByIsEnabled(true); return tools.stream() - .map(toolConvertor::toDTO).collect(Collectors.toList()); + .map(this::toDTO).collect(Collectors.toList()); } @Override public ToolDTO saveTool(ToolDTO toolDTO) { Tool tool = saveToolFromDTO(toolDTO, getCurrentUser()); - return toolConvertor.toDTO(toolRepository.saveAndFlush(tool)); + return toDTO(toolRepository.saveAndFlush(tool)); } private Tool saveToolFromDTO(ToolDTO toolDTO, UserEntity currentUser) { - Tool tool = toolConvertor.toEntity(toolDTO); + Tool tool = toEntity(toolDTO); if (toolDTO.getId() == null) { tool.setCreatedBy(currentUser); } @@ -45,7 +48,7 @@ private Tool saveToolFromDTO(ToolDTO toolDTO, UserEntity currentUser) { @Override public ToolDTO getById(Integer id) { - return toolConvertor.toDTO(toolRepository.findOne(id)); + return toDTO(toolRepository.findOne(id)); } @Override @@ -57,4 +60,61 @@ private boolean canManageTools() { return Stream.of("tool:put", "tool:post", "tool:*:delete") .allMatch(permission -> SecurityUtils.getSubject().isPermitted(permission)); } + + Tool toEntity(ToolDTO toolDTO) { + boolean isNewTool = toolDTO.getId() == null; + Tool tool = isNewTool ? new Tool() : toolRepository.findOne(toolDTO.getId()); + Instant currentInstant = Instant.now(); + if (isNewTool) { + setCreationDetails(tool, currentInstant); + } else { + setModificationDetails(tool, currentInstant); + } + updateToolFromDTO(tool, toolDTO); + return tool; + } + + private void setCreationDetails(Tool tool, Instant currentInstant) { + tool.setCreatedDate(Date.from(currentInstant)); + tool.setCreatedBy(getCurrentUser()); + } + + private void setModificationDetails(Tool tool, Instant currentInstant) { + tool.setModifiedDate(Date.from(currentInstant)); + tool.setModifiedBy(getCurrentUser()); + } + + private void updateToolFromDTO(Tool tool, ToolDTO toolDTO) { + Optional.ofNullable(toolDTO.getName()).ifPresent(tool::setName); + Optional.ofNullable(toolDTO.getUrl()).ifPresent(tool::setUrl); + Optional.ofNullable(toolDTO.getDescription()).ifPresent(tool::setDescription); + Optional.ofNullable(toolDTO.getEnabled()).ifPresent(tool::setEnabled); + } + + ToolDTO toDTO(Tool tool) { + return Optional.ofNullable(tool) + .map(t -> { + ToolDTO toolDTO = new ToolDTO(); + toolDTO.setId(t.getId()); + toolDTO.setName(t.getName()); + toolDTO.setUrl(t.getUrl()); + toolDTO.setDescription(t.getDescription()); + Optional.ofNullable(tool.getCreatedBy()) + .map(UserEntity::getId) + .map(userRepository::findOne) + .map(UserEntity::getName) + .ifPresent(toolDTO::setCreatedByName); + Optional.ofNullable(tool.getModifiedBy()) + .map(UserEntity::getId) + .map(userRepository::findOne) + .map(UserEntity::getName) + .ifPresent(toolDTO::setModifiedByName); + toolDTO.setCreatedDate(t.getCreatedDate() != null ? new SimpleDateFormat(DATE_TIME_FORMAT).format(t.getCreatedDate()) : null); + toolDTO.setModifiedDate(t.getModifiedDate() != null ? new SimpleDateFormat(DATE_TIME_FORMAT).format(t.getModifiedDate()) : null); + toolDTO.setEnabled(t.getEnabled()); + return toolDTO; + }) + .orElse(null); + } + } \ No newline at end of file diff --git a/src/main/java/org/ohdsi/webapi/tool/converter/ToolConvertor.java b/src/main/java/org/ohdsi/webapi/tool/converter/ToolConvertor.java deleted file mode 100644 index 3b31f6144e..0000000000 --- a/src/main/java/org/ohdsi/webapi/tool/converter/ToolConvertor.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.ohdsi.webapi.tool.converter; - -import org.ohdsi.webapi.service.AbstractDaoService; -import org.ohdsi.webapi.shiro.Entities.UserEntity; -import org.ohdsi.webapi.shiro.Entities.UserRepository; -import org.ohdsi.webapi.shiro.PermissionManager; -import org.ohdsi.webapi.tool.Tool; -import org.ohdsi.webapi.tool.ToolRepository; -import org.ohdsi.webapi.tool.dto.ToolDTO; -import org.ohdsi.webapi.util.DateUtils; -import org.springframework.stereotype.Component; - -import java.time.Instant; -import java.util.Date; -import java.util.Optional; - -@Component -public class ToolConvertor extends AbstractDaoService { - private final ToolRepository toolRepository; - private final UserRepository userRepository; - - public ToolConvertor(ToolRepository toolRepository, UserRepository userRepository) { - this.toolRepository = toolRepository; - this.userRepository = userRepository; - } - - public Tool toEntity(ToolDTO toolDTO) { - boolean isNewTool = toolDTO.getId() == null; - Tool tool = isNewTool ? new Tool() : toolRepository.findOne(toolDTO.getId()); - Instant currentInstant = Instant.now(); - if (isNewTool) { - setCreationDetails(tool, currentInstant); - } else { - setModificationDetails(tool, currentInstant); - } - updateToolFromDTO(tool, toolDTO); - return tool; - } - - private void setCreationDetails(Tool tool, Instant currentInstant) { - tool.setCreatedDate(Date.from(currentInstant)); - tool.setCreatedBy(getCurrentUser()); - } - - private void setModificationDetails(Tool tool, Instant currentInstant) { - tool.setModifiedDate(Date.from(currentInstant)); - tool.setModifiedBy(getCurrentUser()); - } - - private void updateToolFromDTO(Tool tool, ToolDTO toolDTO) { - Optional.ofNullable(toolDTO.getName()).ifPresent(tool::setName); - Optional.ofNullable(toolDTO.getUrl()).ifPresent(tool::setUrl); - Optional.ofNullable(toolDTO.getDescription()).ifPresent(tool::setDescription); - Optional.ofNullable(toolDTO.getEnabled()).ifPresent(tool::setEnabled); - } - - public ToolDTO toDTO(Tool tool) { - return Optional.ofNullable(tool) - .map(t -> { - ToolDTO toolDTO = new ToolDTO(); - toolDTO.setId(t.getId()); - toolDTO.setName(t.getName()); - toolDTO.setUrl(t.getUrl()); - toolDTO.setDescription(t.getDescription()); - Optional.ofNullable(tool.getCreatedBy()) - .map(UserEntity::getId) - .map(userRepository::findOne) - .map(UserEntity::getName) - .ifPresent(toolDTO::setCreatedByName); - Optional.ofNullable(tool.getModifiedBy()) - .map(UserEntity::getId) - .map(userRepository::findOne) - .map(UserEntity::getName) - .ifPresent(toolDTO::setModifiedByName); - toolDTO.setCreatedDate(DateUtils.dateToString(t.getCreatedDate())); - toolDTO.setModifiedDate(DateUtils.dateToString(t.getModifiedDate())); - toolDTO.setEnabled(t.getEnabled()); - return toolDTO; - }) - .orElse(null); - } -} diff --git a/src/main/java/org/ohdsi/webapi/util/DateUtils.java b/src/main/java/org/ohdsi/webapi/util/DateUtils.java deleted file mode 100644 index addfb0ce00..0000000000 --- a/src/main/java/org/ohdsi/webapi/util/DateUtils.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.ohdsi.webapi.util; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; - -public class DateUtils { - private static final String DATE_FORMAT = "yyyy-MM-dd"; - private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; - - public static String dateToString(Date date) { - if (date == null) return null; - DateFormat df = new SimpleDateFormat(DATE_TIME_FORMAT); - return df.format(date); - } -} diff --git a/src/main/resources/db/migration/postgresql/V2.13.1.20231213141052__create_table_tools.sql b/src/main/resources/db/migration/postgresql/V2.13.1.20231213141052__create_table_tools.sql deleted file mode 100644 index 27f01965a2..0000000000 --- a/src/main/resources/db/migration/postgresql/V2.13.1.20231213141052__create_table_tools.sql +++ /dev/null @@ -1,18 +0,0 @@ -CREATE TABLE IF NOT EXISTS ${ohdsiSchema}.tool ( - id BIGINT, - name VARCHAR(255) NOT NULL, - url VARCHAR(1000) NOT NULL, - description VARCHAR(1000), - is_enabled BOOLEAN, - created_by_id INTEGER, - modified_by_id INTEGER, - created_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT (now()), - modified_date TIMESTAMP WITH TIME ZONE -); - -ALTER TABLE ${ohdsiSchema}.tool ADD CONSTRAINT PK_tool PRIMARY KEY (id); - -ALTER TABLE ${ohdsiSchema}.tool ADD CONSTRAINT fk_tool_ser_user_creator FOREIGN KEY (created_by_id) REFERENCES ${ohdsiSchema}.sec_user(id); -ALTER TABLE ${ohdsiSchema}.tool ADD CONSTRAINT fk_tool_ser_user_updater FOREIGN KEY (modified_by_id) REFERENCES ${ohdsiSchema}.sec_user(id); - -CREATE SEQUENCE ${ohdsiSchema}.tool_seq START WITH 1 INCREMENT BY 1 MAXVALUE 9223372036854775807 NO CYCLE; \ No newline at end of file diff --git a/src/main/resources/db/migration/postgresql/V2.14.0.20240506100635__add_delete_tool_permission_if_not_exists.sql b/src/main/resources/db/migration/postgresql/V2.14.0.20240506100635__add_delete_tool_permission_if_not_exists.sql deleted file mode 100644 index 32480b5009..0000000000 --- a/src/main/resources/db/migration/postgresql/V2.14.0.20240506100635__add_delete_tool_permission_if_not_exists.sql +++ /dev/null @@ -1,18 +0,0 @@ -INSERT INTO ${ohdsiSchema}.sec_permission (id, value, description) -SELECT nextval('${ohdsiSchema}.sec_permission_id_seq'), 'tool:*:delete', 'Delete Tool' -WHERE NOT EXISTS ( - SELECT NULL FROM ${ohdsiSchema}.sec_permission - WHERE value = 'tool:*:delete' -); - -INSERT INTO ${ohdsiSchema}.sec_role_permission(id, role_id, permission_id) -SELECT nextval('${ohdsiSchema}.sec_role_permission_sequence'), sr.id, sp.id -FROM ${ohdsiSchema}.sec_permission SP, ${ohdsiSchema}.sec_role sr -WHERE sp.value IN ( - 'tool:*:delete' - ) AND sr.name IN ('admin') - AND NOT EXISTS ( - SELECT NULL FROM ${ohdsiSchema}.sec_role_permission - WHERE permission_id = sp.id and role_id = sr.id); - - diff --git a/src/main/resources/db/migration/postgresql/V2.14.0.20240226195200__tools_module_permissions.sql b/src/main/resources/db/migration/postgresql/V2.15.0.20231213141052__create_table_tools_and_permissions.sql similarity index 62% rename from src/main/resources/db/migration/postgresql/V2.14.0.20240226195200__tools_module_permissions.sql rename to src/main/resources/db/migration/postgresql/V2.15.0.20231213141052__create_table_tools_and_permissions.sql index ecd44ce809..765948bd7f 100644 --- a/src/main/resources/db/migration/postgresql/V2.14.0.20240226195200__tools_module_permissions.sql +++ b/src/main/resources/db/migration/postgresql/V2.15.0.20231213141052__create_table_tools_and_permissions.sql @@ -1,3 +1,22 @@ +CREATE TABLE IF NOT EXISTS ${ohdsiSchema}.tool ( + id BIGINT, + name VARCHAR(255) NOT NULL, + url VARCHAR(1000) NOT NULL, + description VARCHAR(1000), + is_enabled BOOLEAN, + created_by_id INTEGER, + modified_by_id INTEGER, + created_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT (now()), + modified_date TIMESTAMP WITH TIME ZONE +); + +ALTER TABLE ${ohdsiSchema}.tool ADD CONSTRAINT PK_tool PRIMARY KEY (id); + +ALTER TABLE ${ohdsiSchema}.tool ADD CONSTRAINT fk_tool_ser_user_creator FOREIGN KEY (created_by_id) REFERENCES ${ohdsiSchema}.sec_user(id); +ALTER TABLE ${ohdsiSchema}.tool ADD CONSTRAINT fk_tool_ser_user_updater FOREIGN KEY (modified_by_id) REFERENCES ${ohdsiSchema}.sec_user(id); + +CREATE SEQUENCE ${ohdsiSchema}.tool_seq START WITH 1 INCREMENT BY 1 MAXVALUE 9223372036854775807 NO CYCLE; + INSERT INTO ${ohdsiSchema}.sec_permission(id, value, description) VALUES (nextval('${ohdsiSchema}.sec_permission_id_seq'), 'tool:post', 'Create Tool'); INSERT INTO ${ohdsiSchema}.sec_permission(id, value, description) VALUES @@ -26,4 +45,4 @@ FROM ${ohdsiSchema}.sec_permission SP, ${ohdsiSchema}.sec_role sr WHERE sp.value IN ( 'tool:get', 'tool:*:get' - ) AND sr.name IN ('Atlas users'); \ No newline at end of file + ) AND sr.name IN ('Atlas users'); From 4fd63801a573658e4397e067a16c1ab8bbcbe20d Mon Sep 17 00:00:00 2001 From: alex-odysseus Date: Tue, 17 Dec 2024 13:04:04 +0100 Subject: [PATCH 18/20] ToolRepository method name changes after property renaming in Tool --- src/main/java/org/ohdsi/webapi/tool/ToolRepository.java | 2 +- src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/ohdsi/webapi/tool/ToolRepository.java b/src/main/java/org/ohdsi/webapi/tool/ToolRepository.java index 9ed4f36a0f..d18ea106fc 100644 --- a/src/main/java/org/ohdsi/webapi/tool/ToolRepository.java +++ b/src/main/java/org/ohdsi/webapi/tool/ToolRepository.java @@ -7,5 +7,5 @@ @Repository public interface ToolRepository extends JpaRepository { - List findAllByIsEnabled(boolean isEnabled); + List findAllByEnabled(boolean enabled); } diff --git a/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java b/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java index 3dc17dd3b1..52a498b3cc 100644 --- a/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java +++ b/src/main/java/org/ohdsi/webapi/tool/ToolServiceImpl.java @@ -26,7 +26,7 @@ public ToolServiceImpl(ToolRepository toolRepository) { @Override public List getTools() { - List tools = (isAdmin() || canManageTools()) ? toolRepository.findAll() : toolRepository.findAllByIsEnabled(true); + List tools = (isAdmin() || canManageTools()) ? toolRepository.findAll() : toolRepository.findAllByEnabled(true); return tools.stream() .map(this::toDTO).collect(Collectors.toList()); } From fdf2d791f866a29ef8a56ea63a2a8f06de8b2a2b Mon Sep 17 00:00:00 2001 From: alex-odysseus Date: Wed, 8 Jan 2025 14:26:47 +0100 Subject: [PATCH 19/20] Aligning with the permissions notation from the migration script --- .../org/ohdsi/webapi/security/model/ToolPermissionSchema.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java b/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java index 99ff7f7e37..ca73e8f6a5 100644 --- a/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java +++ b/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java @@ -9,8 +9,8 @@ public class ToolPermissionSchema extends EntityPermissionSchema { private static Map writePermissions = new HashMap() {{ put("tool:%s:delete", "Delete Tool with id = %s"); - put("tool:%s:put", "Update Tool with id = %s"); - put("tool:%s:post", "Create Tool with id = %s"); + put("tool:put", "Update a Tool"); + put("tool:post", "Create a Tool"); }}; private static Map readPermissions = new HashMap() { { From ad014aba6d889f7d53f69d2f50775e4d9049b030 Mon Sep 17 00:00:00 2001 From: alex-odysseus Date: Mon, 17 Feb 2025 18:32:50 +0100 Subject: [PATCH 20/20] Removing malformed entries from the permission schema correcting a mistake being introduced by the previous commit fdf2d79 --- .../org/ohdsi/webapi/security/model/ToolPermissionSchema.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java b/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java index ca73e8f6a5..5ebd455092 100644 --- a/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java +++ b/src/main/java/org/ohdsi/webapi/security/model/ToolPermissionSchema.java @@ -9,8 +9,6 @@ public class ToolPermissionSchema extends EntityPermissionSchema { private static Map writePermissions = new HashMap() {{ put("tool:%s:delete", "Delete Tool with id = %s"); - put("tool:put", "Update a Tool"); - put("tool:post", "Create a Tool"); }}; private static Map readPermissions = new HashMap() { {