Skip to content

Commit fb6adac

Browse files
BryanMLimahsato03bernardodemarcosureshanaparti
authored
GUI whitelabel runtime system (#8942)
* Add first version * Add guithemedetails join * Update since and remove extra line * Limit information on API response for non admin users * Add base files for preset themes * Add miising license * Revert cookie check * Fix imports * Fix pre-commit * Address log4j2 string to format review and add license to css files * Fix infinite loading * Move event details to service implementation * Move view to a specific view file * Refactoring gui theme classes * Normalize package name * Address Henrique review * Fix create table SQL * Add interface for Dao classes * Remove extra tabs * Address unauthorized call when 2FA is enabled * Remove trailing whitespaces * Apply suggestions from code review Co-authored-by: Suresh Kumar Anaparti <[email protected]> --------- Co-authored-by: Henrique Sato <[email protected]> Co-authored-by: Bernardo De Marco Gonçalves <[email protected]> Co-authored-by: Suresh Kumar Anaparti <[email protected]>
1 parent 6059724 commit fb6adac

File tree

45 files changed

+5519
-20
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+5519
-20
lines changed

api/src/main/java/com/cloud/event/EventTypes.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,11 @@ public class EventTypes {
809809
public static final String VM_LEASE_CANCELLED = "VM.LEASE.CANCELLED";
810810
public static final String VM_LEASE_EXPIRING = "VM.LEASE.EXPIRING";
811811

812+
// GUI Theme
813+
public static final String EVENT_GUI_THEME_CREATE = "GUI.THEME.CREATE";
814+
public static final String EVENT_GUI_THEME_REMOVE = "GUI.THEME.REMOVE";
815+
public static final String EVENT_GUI_THEME_UPDATE = "GUI.THEME.UPDATE";
816+
812817
static {
813818

814819
// TODO: need a way to force author adding event types to declare the entity details as well, with out braking
@@ -1312,6 +1317,11 @@ public class EventTypes {
13121317
entityEventDetails.put(VM_LEASE_EXPIRING, VirtualMachine.class);
13131318
entityEventDetails.put(VM_LEASE_DISABLED, VirtualMachine.class);
13141319
entityEventDetails.put(VM_LEASE_CANCELLED, VirtualMachine.class);
1320+
1321+
// GUI theme
1322+
entityEventDetails.put(EVENT_GUI_THEME_CREATE, "GuiTheme");
1323+
entityEventDetails.put(EVENT_GUI_THEME_REMOVE, "GuiTheme");
1324+
entityEventDetails.put(EVENT_GUI_THEME_UPDATE, "GuiTheme");
13151325
}
13161326

13171327
public static boolean isNetworkEvent(String eventType) {

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,6 +1256,22 @@ public class ApiConstants {
12561256

12571257
public static final String VMWARE_DC = "vmwaredc";
12581258

1259+
public static final String CSS = "css";
1260+
1261+
public static final String JSON_CONFIGURATION = "jsonconfiguration";
1262+
1263+
public static final String COMMON_NAMES = "commonnames";
1264+
1265+
public static final String COMMON_NAME = "commonname";
1266+
1267+
public static final String DOMAIN_IDS = "domainids";
1268+
1269+
public static final String SHOW_PUBLIC = "showpublic";
1270+
1271+
public static final String LIST_ONLY_DEFAULT_THEME = "listonlydefaulttheme";
1272+
1273+
public static final String RECURSIVE_DOMAINS = "recursivedomains";
1274+
12591275
/**
12601276
* This enum specifies IO Drivers, each option controls specific policies on I/O.
12611277
* Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0).

api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
import org.apache.cloudstack.api.response.GuestOsMappingResponse;
6565
import org.apache.cloudstack.api.response.GuestVlanRangeResponse;
6666
import org.apache.cloudstack.api.response.GuestVlanResponse;
67+
import org.apache.cloudstack.api.response.GuiThemeResponse;
6768
import org.apache.cloudstack.api.response.HostForMigrationResponse;
6869
import org.apache.cloudstack.api.response.HostResponse;
6970
import org.apache.cloudstack.api.response.HypervisorCapabilitiesResponse;
@@ -150,6 +151,7 @@
150151
import org.apache.cloudstack.direct.download.DirectDownloadCertificate;
151152
import org.apache.cloudstack.direct.download.DirectDownloadCertificateHostMap;
152153
import org.apache.cloudstack.direct.download.DirectDownloadManager;
154+
import org.apache.cloudstack.gui.theme.GuiThemeJoin;
153155
import org.apache.cloudstack.management.ManagementServerHost;
154156
import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule;
155157
import org.apache.cloudstack.region.PortableIp;
@@ -579,4 +581,6 @@ List<TemplateResponse> createTemplateResponses(ResponseView view, VirtualMachine
579581
SharedFSResponse createSharedFSResponse(ResponseView view, SharedFS sharedFS);
580582

581583
void updateTemplateIsoResponsesForIcons(List<TemplateResponse> responses, ResourceTag.ResourceObjectType type);
584+
585+
GuiThemeResponse createGuiThemeResponse(GuiThemeJoin guiThemeJoin);
582586
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.api.command.user.gui.theme;
18+
19+
import org.apache.cloudstack.acl.RoleType;
20+
import org.apache.cloudstack.api.APICommand;
21+
import org.apache.cloudstack.api.ApiConstants;
22+
import org.apache.cloudstack.api.ApiErrorCode;
23+
import org.apache.cloudstack.api.BaseCmd;
24+
import org.apache.cloudstack.api.Parameter;
25+
import org.apache.cloudstack.api.ServerApiException;
26+
import org.apache.cloudstack.api.response.GuiThemeResponse;
27+
import org.apache.cloudstack.context.CallContext;
28+
import org.apache.cloudstack.gui.theme.GuiTheme;
29+
import org.apache.cloudstack.gui.theme.GuiThemeJoin;
30+
import org.apache.cloudstack.gui.theme.GuiThemeService;
31+
32+
import javax.inject.Inject;
33+
34+
@APICommand(name = "createGuiTheme", description = "Creates a customized GUI theme for a set of Common Names (fixed or wildcard), a set of domain UUIDs, and/or a set of " +
35+
"account UUIDs.", responseObject = GuiThemeResponse.class, entityType = {GuiTheme.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
36+
since = "4.21.0.0", authorized = {RoleType.Admin})
37+
public class CreateGuiThemeCmd extends BaseCmd {
38+
39+
@Inject
40+
GuiThemeService guiThemeService;
41+
42+
@Parameter(name = ApiConstants.NAME, required = true, type = CommandType.STRING, length = 2048, description = "A name to identify the theme.")
43+
private String name;
44+
45+
@Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, length = 4096, description = "A description for the theme.")
46+
private String description;
47+
48+
@Parameter(name = ApiConstants.CSS, type = CommandType.STRING, length = 65535, description = "The CSS to be retrieved and imported into the GUI " +
49+
"when matching the theme access configurations.")
50+
private String css;
51+
52+
@Parameter(name = ApiConstants.JSON_CONFIGURATION, type = CommandType.STRING, length = 65535, description = "The JSON with the configurations to be " +
53+
"retrieved and imported into the GUI when matching the theme access configurations.")
54+
private String jsonConfiguration;
55+
56+
@Parameter(name = ApiConstants.COMMON_NAMES, type = CommandType.STRING, length = 65535, description = "A set of Common Names (CN) (fixed or " +
57+
"wildcard) separated by comma that can retrieve the theme; e.g.: *acme.com,acme2.com")
58+
private String commonNames;
59+
60+
@Parameter(name = ApiConstants.DOMAIN_IDS, type = CommandType.STRING, length = 65535, description = "A set of domain UUIDs (also known as ID for " +
61+
"the end-user) separated by comma that can retrieve the theme.")
62+
private String domainIds;
63+
64+
@Parameter(name = ApiConstants.ACCOUNT_IDS, type = CommandType.STRING, length = 65535, description = "A set of account UUIDs (also known as ID for" +
65+
" the end-user) separated by comma that can retrieve the theme.")
66+
private String accountIds;
67+
68+
@Parameter(name = ApiConstants.IS_PUBLIC, type = CommandType.BOOLEAN, description = "Defines whether a theme can be retrieved by anyone when only " +
69+
"the `commonNames` is informed. If the `domainIds` or `accountIds` is informed, it is considered as `false`.")
70+
private Boolean isPublic = true;
71+
72+
@Parameter(name = ApiConstants.RECURSIVE_DOMAINS, type = CommandType.BOOLEAN, description = "Defines whether the subdomains of the informed domains are considered. Default " +
73+
"value is false.")
74+
private Boolean recursiveDomains = false;
75+
76+
public String getName() {
77+
return name;
78+
}
79+
80+
public String getDescription() {
81+
return description;
82+
}
83+
84+
public String getCss() {
85+
return css;
86+
}
87+
88+
public String getJsonConfiguration() {
89+
return jsonConfiguration;
90+
}
91+
92+
public String getCommonNames() {
93+
return commonNames;
94+
}
95+
96+
public String getDomainIds() {
97+
return domainIds;
98+
}
99+
100+
public String getAccountIds() {
101+
return accountIds;
102+
}
103+
104+
public Boolean getPublic() {
105+
return isPublic;
106+
}
107+
108+
public Boolean getRecursiveDomains() {
109+
return recursiveDomains;
110+
}
111+
112+
@Override
113+
public void execute() {
114+
GuiThemeJoin guiThemeJoin = guiThemeService.createGuiTheme(this);
115+
116+
if (guiThemeJoin == null) {
117+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create the GUI theme.");
118+
}
119+
120+
GuiThemeResponse response = _responseGenerator.createGuiThemeResponse(guiThemeJoin);
121+
response.setResponseName(getCommandName());
122+
this.setResponseObject(response);
123+
}
124+
125+
@Override
126+
public long getEntityOwnerId() {
127+
return CallContext.current().getCallingAccountId();
128+
}
129+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.api.command.user.gui.theme;
18+
19+
import org.apache.cloudstack.acl.RoleType;
20+
import org.apache.cloudstack.api.APICommand;
21+
import org.apache.cloudstack.api.ApiConstants;
22+
import org.apache.cloudstack.api.BaseListCmd;
23+
import org.apache.cloudstack.api.Parameter;
24+
import org.apache.cloudstack.api.response.AccountResponse;
25+
import org.apache.cloudstack.api.response.DomainResponse;
26+
import org.apache.cloudstack.api.response.GuiThemeResponse;
27+
import org.apache.cloudstack.api.response.ListResponse;
28+
import org.apache.cloudstack.gui.theme.GuiTheme;
29+
import org.apache.cloudstack.gui.theme.GuiThemeService;
30+
31+
import javax.inject.Inject;
32+
33+
@APICommand(name = "listGuiThemes", description = "Lists GUI themes.", responseObject = GuiThemeResponse.class, entityType = {GuiTheme.class},
34+
since = "4.21.0.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin, RoleType.User, RoleType.DomainAdmin,
35+
RoleType.ResourceAdmin})
36+
public class ListGuiThemesCmd extends BaseListCmd {
37+
38+
@Inject
39+
GuiThemeService guiThemeService;
40+
41+
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, description = "The theme ID.", entityType = GuiThemeResponse.class)
42+
private Long id;
43+
44+
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "The name of the theme.")
45+
private String name;
46+
47+
@Parameter(name = ApiConstants.COMMON_NAME, type = CommandType.STRING, description = "The internet Common Name (CN) to be filtered.")
48+
private String commonName;
49+
50+
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "The ID of the domain to be filtered.")
51+
private Long domainId;
52+
53+
@Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.UUID, entityType = AccountResponse.class, description = "The ID of the account to be filtered.")
54+
private Long accountId;
55+
56+
@Parameter(name = ApiConstants.LIST_ALL, type = CommandType.BOOLEAN, description = "Whether to list all themes.")
57+
private boolean listAll = false;
58+
59+
@Parameter(name = ApiConstants.SHOW_REMOVED, type = CommandType.BOOLEAN, description = "Whether to list removed themes.")
60+
private boolean showRemoved = false;
61+
62+
@Parameter(name = ApiConstants.SHOW_PUBLIC, type = CommandType.BOOLEAN, description = "Whether to list public themes.")
63+
private Boolean showPublic;
64+
65+
@Parameter(name = ApiConstants.LIST_ONLY_DEFAULT_THEME, type = CommandType.BOOLEAN, description = "Whether to only list the default theme.")
66+
private boolean listOnlyDefaultTheme = false;
67+
68+
public Long getId() {
69+
return id;
70+
}
71+
72+
public String getName() {
73+
return name;
74+
}
75+
76+
public String getCommonName() {
77+
return commonName;
78+
}
79+
80+
public Long getDomainId() {
81+
return domainId;
82+
}
83+
84+
public Long getAccountId() {
85+
return accountId;
86+
}
87+
88+
public boolean getListAll() {
89+
return listAll;
90+
}
91+
92+
public boolean getShowRemoved() {
93+
return showRemoved;
94+
}
95+
96+
public Boolean getShowPublic() {
97+
return showPublic;
98+
}
99+
100+
public boolean getListOnlyDefaultTheme() {
101+
return listOnlyDefaultTheme;
102+
}
103+
104+
@Override
105+
public void execute() {
106+
ListResponse<GuiThemeResponse> response = guiThemeService.listGuiThemes(this);
107+
response.setResponseName(getCommandName());
108+
this.setResponseObject(response);
109+
}
110+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.api.command.user.gui.theme;
18+
19+
import org.apache.cloudstack.acl.RoleType;
20+
import org.apache.cloudstack.api.APICommand;
21+
import org.apache.cloudstack.api.ApiConstants;
22+
import org.apache.cloudstack.api.BaseCmd;
23+
import org.apache.cloudstack.api.Parameter;
24+
import org.apache.cloudstack.api.response.GuiThemeResponse;
25+
import org.apache.cloudstack.api.response.SuccessResponse;
26+
import org.apache.cloudstack.context.CallContext;
27+
import org.apache.cloudstack.gui.theme.GuiTheme;
28+
import org.apache.cloudstack.gui.theme.GuiThemeService;
29+
30+
import javax.inject.Inject;
31+
32+
@APICommand(name = "removeGuiTheme", description = "Removes an existing GUI theme.", responseObject = GuiThemeResponse.class, entityType = {GuiTheme.class},
33+
since = "4.21.0.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin})
34+
public class RemoveGuiThemeCmd extends BaseCmd {
35+
36+
@Inject
37+
GuiThemeService guiThemeService;
38+
39+
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = GuiThemeResponse.class, required = true,
40+
description = "The unique identifier of the GUI theme to be removed.")
41+
private Long id;
42+
43+
public Long getId() {
44+
return id;
45+
}
46+
47+
@Override
48+
public void execute() {
49+
guiThemeService.removeGuiTheme(this);
50+
final SuccessResponse response = new SuccessResponse();
51+
response.setResponseName(getCommandName());
52+
response.setSuccess(true);
53+
setResponseObject(response);
54+
}
55+
56+
@Override
57+
public long getEntityOwnerId() {
58+
return CallContext.current().getCallingAccountId();
59+
}
60+
}

0 commit comments

Comments
 (0)