From fd36c01a81777404de374359652aab15ff803dea Mon Sep 17 00:00:00 2001 From: Nirmal Sarswat Date: Mon, 20 May 2024 15:44:53 +0530 Subject: [PATCH 1/2] chore:system theme migration --- .../migrations/RepositoryHelperMethods.java | 56 ++++++++++ .../ce/V10__createSystemThemes.java | 101 ++++++++++++++++++ ...__cleanPermissionsInPermissionGroups.java} | 2 +- 3 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/ce/V10__createSystemThemes.java rename app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/ce/{V10__cleanPermissionsInPermissionGroups.java => V11__cleanPermissionsInPermissionGroups.java} (85%) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/RepositoryHelperMethods.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/RepositoryHelperMethods.java index 90cd888ad45..091d897d9c8 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/RepositoryHelperMethods.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/RepositoryHelperMethods.java @@ -4,6 +4,7 @@ import com.appsmith.server.domains.Config; import com.appsmith.server.domains.PermissionGroup; import com.appsmith.server.domains.Tenant; +import com.appsmith.server.domains.Theme; import com.appsmith.server.domains.User; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; @@ -19,6 +20,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.UUID; @@ -214,4 +216,58 @@ public Tenant saveTenant(Tenant tenant) throws JsonProcessingException { id); return tenant; } + + public Theme getTheme(String name, boolean isSystemTheme) { + String sqlQuery = "SELECT * FROM theme WHERE name = ? AND is_system_theme = ?"; + RowMapper rowMapper = (rs, rowNum) -> { + Theme theme = new Theme(); + theme.setId(rs.getString("id")); + theme.setName(rs.getString("name")); + theme.setDisplayName(rs.getString("display_name")); + theme.setStylesheet(mapObject(rs.getString("stylesheet"), new TypeReference>() {})); + theme.setProperties(mapObject(rs.getString("properties"), new TypeReference>() {})); + theme.setConfig(mapObject(rs.getString("config"), new TypeReference>() {})); + theme.setSystemTheme(rs.getBoolean("is_system_theme")); + return theme; + }; + try { + return jdbcTemplate.queryForObject(sqlQuery, rowMapper, name, isSystemTheme); + } catch (EmptyResultDataAccessException e) { + return null; + } + } + + public Theme saveTheme(Theme theme) throws JsonProcessingException { + String id = theme.getId(); + String insertInstanceConfigurationQuery = + "UPDATE theme SET name = ?, display_name = ?, config = cast(? as jsonb), properties = cast(? as jsonb), stylesheet = cast(? as jsonb), policies = cast(? as jsonb), updated_at = now() WHERE id = ?"; + jdbcTemplate.update( + insertInstanceConfigurationQuery, + theme.getName(), + theme.getDisplayName(), + JsonHelper.convertToString(theme.getConfig()), + JsonHelper.convertToString(theme.getProperties()), + JsonHelper.convertToString(theme.getStylesheet()), + JsonHelper.convertToString(theme.getPolicies()), + id); + return theme; + } + + public Theme createTheme(Theme theme) throws JsonProcessingException { + String id = UUID.randomUUID().toString(); + String insertInstanceConfigurationQuery = + "INSERT INTO theme (id, name, display_name, config, properties, stylesheet, is_system_theme, policies, created_at, updated_at) VALUES (?, ?, ?, cast(? as jsonb), cast(? as jsonb), cast(? as jsonb), ?, cast(? as jsonb), now(), now())"; + jdbcTemplate.update( + insertInstanceConfigurationQuery, + id, + theme.getName(), + theme.getDisplayName(), + JsonHelper.convertToString(theme.getConfig()), + JsonHelper.convertToString(theme.getProperties()), + JsonHelper.convertToString(theme.getStylesheet()), + theme.isSystemTheme(), + JsonHelper.convertToString(theme.getPolicies())); + theme.setId(id); + return theme; + } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/ce/V10__createSystemThemes.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/ce/V10__createSystemThemes.java new file mode 100644 index 00000000000..c9e604c6975 --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/ce/V10__createSystemThemes.java @@ -0,0 +1,101 @@ +package com.appsmith.server.migrations.ce; + +import com.appsmith.external.converters.ISOStringToInstantConverter; +import com.appsmith.external.models.Policy; +import com.appsmith.server.domains.Config; +import com.appsmith.server.domains.PermissionGroup; +import com.appsmith.server.domains.Theme; +import com.appsmith.server.dtos.Permission; +import com.appsmith.server.migrations.AppsmithJavaMigration; +import com.appsmith.server.migrations.RepositoryHelperMethods; +import com.google.gson.GsonBuilder; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.util.StreamUtils; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.time.Instant; +import java.util.HashSet; +import java.util.Set; + +import static com.appsmith.server.acl.AclPermission.READ_THEMES; +import static com.appsmith.server.constants.ce.FieldNameCE.PERMISSION_GROUP_ID; +import static com.appsmith.server.constants.ce.FieldNameCE.PUBLIC_PERMISSION_GROUP; + +public class V10__createSystemThemes extends AppsmithJavaMigration { + private RepositoryHelperMethods repositoryHelperMethods; + + @Override + public void migrate(JdbcTemplate jdbcTemplate) throws Exception { + repositoryHelperMethods = new RepositoryHelperMethods(jdbcTemplate); + createSystemTheme(); + } + + private void createSystemTheme() throws IOException { + final String themesJson = StreamUtils.copyToString( + new DefaultResourceLoader().getResource("system-themes.json").getInputStream(), + Charset.defaultCharset()); + + Theme[] themes = new GsonBuilder() + .registerTypeAdapter(Instant.class, new ISOStringToInstantConverter()) + .create() + .fromJson(themesJson, Theme[].class); + + Config publicPermissionGroupConfig = repositoryHelperMethods.getConfig(PUBLIC_PERMISSION_GROUP); + if (publicPermissionGroupConfig == null) { + throw new IllegalStateException("Public permission group not found in the database."); + } + + String permissionGroupId = publicPermissionGroupConfig.getConfig().getAsString(PERMISSION_GROUP_ID); + + PermissionGroup publicPermissionGroup = repositoryHelperMethods.getPermissionGroup(permissionGroupId); + + // Initialize the permissions for the role + HashSet permissions = new HashSet<>(); + if (publicPermissionGroup.getPermissions() != null) { + permissions.addAll(publicPermissionGroup.getPermissions()); + } + + Policy policyWithCurrentPermission = Policy.builder() + .permission(READ_THEMES.getValue()) + .permissionGroups(Set.of(publicPermissionGroup.getId())) + .build(); + + for (Theme theme : themes) { + theme.setSystemTheme(true); + theme.setCreatedAt(Instant.now()); + theme.setPolicies(new HashSet<>(Set.of(policyWithCurrentPermission))); + + Theme savedTheme = repositoryHelperMethods.getTheme(theme.getName(), true); + if (savedTheme == null) { // this theme does not exist, create it + savedTheme = repositoryHelperMethods.createTheme(theme); + } else { // theme already found, update + savedTheme.setDisplayName(theme.getDisplayName()); + savedTheme.setPolicies(theme.getPolicies()); + savedTheme.setConfig(theme.getConfig()); + savedTheme.setProperties(theme.getProperties()); + savedTheme.setStylesheet(theme.getStylesheet()); + if (savedTheme.getCreatedAt() == null) { + savedTheme.setCreatedAt(Instant.now()); + } + repositoryHelperMethods.saveTheme(savedTheme); + } + + // Add the access to this theme to the public permission group + Theme finalSavedTheme = savedTheme; + boolean isThemePermissionPresent = permissions.stream() + .filter(p -> p.getAclPermission().equals(READ_THEMES) + && p.getDocumentId().equals(finalSavedTheme.getId())) + .findFirst() + .isPresent(); + if (!isThemePermissionPresent) { + permissions.add(new Permission(finalSavedTheme.getId(), READ_THEMES)); + } + } + + // Finally save the role which gives access to all the system themes to the anonymous user. + publicPermissionGroup.setPermissions(permissions); + repositoryHelperMethods.savePermissionGroup(publicPermissionGroup); + } +} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/ce/V10__cleanPermissionsInPermissionGroups.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/ce/V11__cleanPermissionsInPermissionGroups.java similarity index 85% rename from app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/ce/V10__cleanPermissionsInPermissionGroups.java rename to app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/ce/V11__cleanPermissionsInPermissionGroups.java index 2f1b5aad9f4..a032e9bf907 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/ce/V10__cleanPermissionsInPermissionGroups.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/ce/V11__cleanPermissionsInPermissionGroups.java @@ -3,7 +3,7 @@ import com.appsmith.server.migrations.AppsmithJavaMigration; import org.springframework.jdbc.core.JdbcTemplate; -public class V10__cleanPermissionsInPermissionGroups extends AppsmithJavaMigration { +public class V11__cleanPermissionsInPermissionGroups extends AppsmithJavaMigration { @Override public void migrate(JdbcTemplate jdbcTemplate) throws Exception { String sql = "UPDATE permission_group SET permissions = NULL"; From 04ad6ab8c53c3dd22372a755f3d4fda49351baf8 Mon Sep 17 00:00:00 2001 From: Nirmal Sarswat Date: Mon, 20 May 2024 18:06:44 +0530 Subject: [PATCH 2/2] code refactor --- .../server/migrations/RepositoryHelperMethods.java | 4 ++-- .../migrations/ce/V10__createSystemThemes.java | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/RepositoryHelperMethods.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/RepositoryHelperMethods.java index 091d897d9c8..cd5b121dbd3 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/RepositoryHelperMethods.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/RepositoryHelperMethods.java @@ -239,10 +239,10 @@ public Theme getTheme(String name, boolean isSystemTheme) { public Theme saveTheme(Theme theme) throws JsonProcessingException { String id = theme.getId(); - String insertInstanceConfigurationQuery = + String updateThemeQuery = "UPDATE theme SET name = ?, display_name = ?, config = cast(? as jsonb), properties = cast(? as jsonb), stylesheet = cast(? as jsonb), policies = cast(? as jsonb), updated_at = now() WHERE id = ?"; jdbcTemplate.update( - insertInstanceConfigurationQuery, + updateThemeQuery, theme.getName(), theme.getDisplayName(), JsonHelper.convertToString(theme.getConfig()), diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/ce/V10__createSystemThemes.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/ce/V10__createSystemThemes.java index c9e604c6975..4455d3a7cf7 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/ce/V10__createSystemThemes.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/ce/V10__createSystemThemes.java @@ -1,6 +1,5 @@ package com.appsmith.server.migrations.ce; -import com.appsmith.external.converters.ISOStringToInstantConverter; import com.appsmith.external.models.Policy; import com.appsmith.server.domains.Config; import com.appsmith.server.domains.PermissionGroup; @@ -8,7 +7,9 @@ import com.appsmith.server.dtos.Permission; import com.appsmith.server.migrations.AppsmithJavaMigration; import com.appsmith.server.migrations.RepositoryHelperMethods; -import com.google.gson.GsonBuilder; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.util.StreamUtils; @@ -36,11 +37,10 @@ private void createSystemTheme() throws IOException { final String themesJson = StreamUtils.copyToString( new DefaultResourceLoader().getResource("system-themes.json").getInputStream(), Charset.defaultCharset()); - - Theme[] themes = new GsonBuilder() - .registerTypeAdapter(Instant.class, new ISOStringToInstantConverter()) - .create() - .fromJson(themesJson, Theme[].class); + ObjectMapper mapper = new ObjectMapper(); + mapper.registerModule(new JavaTimeModule()); + mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + Theme[] themes = mapper.readValue(themesJson, Theme[].class); Config publicPermissionGroupConfig = repositoryHelperMethods.getConfig(PUBLIC_PERMISSION_GROUP); if (publicPermissionGroupConfig == null) {