Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Migration for system themes #33587

Merged
merged 2 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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<Theme> 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<Map<String, Object>>() {}));
theme.setProperties(mapObject(rs.getString("properties"), new TypeReference<Map<String, Object>>() {}));
theme.setConfig(mapObject(rs.getString("config"), new TypeReference<Map<String, Object>>() {}));
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 =
vivonk marked this conversation as resolved.
Show resolved Hide resolved
"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;
}
}
Original file line number Diff line number Diff line change
@@ -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()
vivonk marked this conversation as resolved.
Show resolved Hide resolved
.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<Permission> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down