Skip to content

Commit a83f9fc

Browse files
BryanMLimahsato03bernardodemarcosureshanaparti
authored andcommitted
GUI whitelabel runtime system (apache#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 a811075 commit a83f9fc

File tree

44 files changed

+5521
-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.

44 files changed

+5521
-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
@@ -822,6 +822,11 @@ public class EventTypes {
822822
public static final String VM_LEASE_CANCELLED = "VM.LEASE.CANCELLED";
823823
public static final String VM_LEASE_EXPIRING = "VM.LEASE.EXPIRING";
824824

825+
// GUI Theme
826+
public static final String EVENT_GUI_THEME_CREATE = "GUI.THEME.CREATE";
827+
public static final String EVENT_GUI_THEME_REMOVE = "GUI.THEME.REMOVE";
828+
public static final String EVENT_GUI_THEME_UPDATE = "GUI.THEME.UPDATE";
829+
825830
static {
826831

827832
// TODO: need a way to force author adding event types to declare the entity details as well, with out braking
@@ -1332,6 +1337,11 @@ public class EventTypes {
13321337
entityEventDetails.put(VM_LEASE_EXPIRING, VirtualMachine.class);
13331338
entityEventDetails.put(VM_LEASE_DISABLED, VirtualMachine.class);
13341339
entityEventDetails.put(VM_LEASE_CANCELLED, VirtualMachine.class);
1340+
1341+
// GUI theme
1342+
entityEventDetails.put(EVENT_GUI_THEME_CREATE, "GuiTheme");
1343+
entityEventDetails.put(EVENT_GUI_THEME_REMOVE, "GuiTheme");
1344+
entityEventDetails.put(EVENT_GUI_THEME_UPDATE, "GuiTheme");
13351345
}
13361346

13371347
public static boolean isNetworkEvent(String eventType) {

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,8 +1371,27 @@ public class ApiConstants {
13711371
public static final String VMWARE_DC = "vmwaredc";
13721372

13731373
public static final String ISSUED_DATE = "issueddate";
1374+
13741375
public static final String XML_CONFIG = "xmlconfig";
1376+
13751377
public static final String CURRENT_VM_ID = "currentvmid";
1378+
1379+
public static final String CSS = "css";
1380+
1381+
public static final String JSON_CONFIGURATION = "jsonconfiguration";
1382+
1383+
public static final String COMMON_NAMES = "commonnames";
1384+
1385+
public static final String COMMON_NAME = "commonname";
1386+
1387+
public static final String DOMAIN_IDS = "domainids";
1388+
1389+
public static final String SHOW_PUBLIC = "showpublic";
1390+
1391+
public static final String LIST_ONLY_DEFAULT_THEME = "listonlydefaulttheme";
1392+
1393+
public static final String RECURSIVE_DOMAINS = "recursivedomains";
1394+
13761395
/**
13771396
* This enum specifies IO Drivers, each option controls specific policies on I/O.
13781397
* 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;
@@ -582,4 +584,6 @@ List<TemplateResponse> createTemplateResponses(ResponseView view, VirtualMachine
582584
SharedFSResponse createSharedFSResponse(ResponseView view, SharedFS sharedFS);
583585

584586
void updateTemplateIsoResponsesForIcons(List<TemplateResponse> responses, ResourceTag.ResourceObjectType type);
587+
588+
GuiThemeResponse createGuiThemeResponse(GuiThemeJoin guiThemeJoin);
585589
}
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)