mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
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 <sureshkumar.anaparti@gmail.com> --------- Co-authored-by: Henrique Sato <henriquesato2003@gmail.com> Co-authored-by: Bernardo De Marco Gonçalves <bernardomg2004@gmail.com> Co-authored-by: Suresh Kumar Anaparti <sureshkumar.anaparti@gmail.com>
This commit is contained in:
parent
6059724189
commit
fb6adacc51
@ -809,6 +809,11 @@ public class EventTypes {
|
||||
public static final String VM_LEASE_CANCELLED = "VM.LEASE.CANCELLED";
|
||||
public static final String VM_LEASE_EXPIRING = "VM.LEASE.EXPIRING";
|
||||
|
||||
// GUI Theme
|
||||
public static final String EVENT_GUI_THEME_CREATE = "GUI.THEME.CREATE";
|
||||
public static final String EVENT_GUI_THEME_REMOVE = "GUI.THEME.REMOVE";
|
||||
public static final String EVENT_GUI_THEME_UPDATE = "GUI.THEME.UPDATE";
|
||||
|
||||
static {
|
||||
|
||||
// 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 {
|
||||
entityEventDetails.put(VM_LEASE_EXPIRING, VirtualMachine.class);
|
||||
entityEventDetails.put(VM_LEASE_DISABLED, VirtualMachine.class);
|
||||
entityEventDetails.put(VM_LEASE_CANCELLED, VirtualMachine.class);
|
||||
|
||||
// GUI theme
|
||||
entityEventDetails.put(EVENT_GUI_THEME_CREATE, "GuiTheme");
|
||||
entityEventDetails.put(EVENT_GUI_THEME_REMOVE, "GuiTheme");
|
||||
entityEventDetails.put(EVENT_GUI_THEME_UPDATE, "GuiTheme");
|
||||
}
|
||||
|
||||
public static boolean isNetworkEvent(String eventType) {
|
||||
|
||||
@ -1256,6 +1256,22 @@ public class ApiConstants {
|
||||
|
||||
public static final String VMWARE_DC = "vmwaredc";
|
||||
|
||||
public static final String CSS = "css";
|
||||
|
||||
public static final String JSON_CONFIGURATION = "jsonconfiguration";
|
||||
|
||||
public static final String COMMON_NAMES = "commonnames";
|
||||
|
||||
public static final String COMMON_NAME = "commonname";
|
||||
|
||||
public static final String DOMAIN_IDS = "domainids";
|
||||
|
||||
public static final String SHOW_PUBLIC = "showpublic";
|
||||
|
||||
public static final String LIST_ONLY_DEFAULT_THEME = "listonlydefaulttheme";
|
||||
|
||||
public static final String RECURSIVE_DOMAINS = "recursivedomains";
|
||||
|
||||
/**
|
||||
* This enum specifies IO Drivers, each option controls specific policies on I/O.
|
||||
* Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0).
|
||||
|
||||
@ -64,6 +64,7 @@ import org.apache.cloudstack.api.response.GuestOSResponse;
|
||||
import org.apache.cloudstack.api.response.GuestOsMappingResponse;
|
||||
import org.apache.cloudstack.api.response.GuestVlanRangeResponse;
|
||||
import org.apache.cloudstack.api.response.GuestVlanResponse;
|
||||
import org.apache.cloudstack.api.response.GuiThemeResponse;
|
||||
import org.apache.cloudstack.api.response.HostForMigrationResponse;
|
||||
import org.apache.cloudstack.api.response.HostResponse;
|
||||
import org.apache.cloudstack.api.response.HypervisorCapabilitiesResponse;
|
||||
@ -150,6 +151,7 @@ import org.apache.cloudstack.config.ConfigurationGroup;
|
||||
import org.apache.cloudstack.direct.download.DirectDownloadCertificate;
|
||||
import org.apache.cloudstack.direct.download.DirectDownloadCertificateHostMap;
|
||||
import org.apache.cloudstack.direct.download.DirectDownloadManager;
|
||||
import org.apache.cloudstack.gui.theme.GuiThemeJoin;
|
||||
import org.apache.cloudstack.management.ManagementServerHost;
|
||||
import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule;
|
||||
import org.apache.cloudstack.region.PortableIp;
|
||||
@ -579,4 +581,6 @@ public interface ResponseGenerator {
|
||||
SharedFSResponse createSharedFSResponse(ResponseView view, SharedFS sharedFS);
|
||||
|
||||
void updateTemplateIsoResponsesForIcons(List<TemplateResponse> responses, ResourceTag.ResourceObjectType type);
|
||||
|
||||
GuiThemeResponse createGuiThemeResponse(GuiThemeJoin guiThemeJoin);
|
||||
}
|
||||
|
||||
@ -0,0 +1,129 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.user.gui.theme;
|
||||
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.GuiThemeResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.gui.theme.GuiTheme;
|
||||
import org.apache.cloudstack.gui.theme.GuiThemeJoin;
|
||||
import org.apache.cloudstack.gui.theme.GuiThemeService;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@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 " +
|
||||
"account UUIDs.", responseObject = GuiThemeResponse.class, entityType = {GuiTheme.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
|
||||
since = "4.21.0.0", authorized = {RoleType.Admin})
|
||||
public class CreateGuiThemeCmd extends BaseCmd {
|
||||
|
||||
@Inject
|
||||
GuiThemeService guiThemeService;
|
||||
|
||||
@Parameter(name = ApiConstants.NAME, required = true, type = CommandType.STRING, length = 2048, description = "A name to identify the theme.")
|
||||
private String name;
|
||||
|
||||
@Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, length = 4096, description = "A description for the theme.")
|
||||
private String description;
|
||||
|
||||
@Parameter(name = ApiConstants.CSS, type = CommandType.STRING, length = 65535, description = "The CSS to be retrieved and imported into the GUI " +
|
||||
"when matching the theme access configurations.")
|
||||
private String css;
|
||||
|
||||
@Parameter(name = ApiConstants.JSON_CONFIGURATION, type = CommandType.STRING, length = 65535, description = "The JSON with the configurations to be " +
|
||||
"retrieved and imported into the GUI when matching the theme access configurations.")
|
||||
private String jsonConfiguration;
|
||||
|
||||
@Parameter(name = ApiConstants.COMMON_NAMES, type = CommandType.STRING, length = 65535, description = "A set of Common Names (CN) (fixed or " +
|
||||
"wildcard) separated by comma that can retrieve the theme; e.g.: *acme.com,acme2.com")
|
||||
private String commonNames;
|
||||
|
||||
@Parameter(name = ApiConstants.DOMAIN_IDS, type = CommandType.STRING, length = 65535, description = "A set of domain UUIDs (also known as ID for " +
|
||||
"the end-user) separated by comma that can retrieve the theme.")
|
||||
private String domainIds;
|
||||
|
||||
@Parameter(name = ApiConstants.ACCOUNT_IDS, type = CommandType.STRING, length = 65535, description = "A set of account UUIDs (also known as ID for" +
|
||||
" the end-user) separated by comma that can retrieve the theme.")
|
||||
private String accountIds;
|
||||
|
||||
@Parameter(name = ApiConstants.IS_PUBLIC, type = CommandType.BOOLEAN, description = "Defines whether a theme can be retrieved by anyone when only " +
|
||||
"the `commonNames` is informed. If the `domainIds` or `accountIds` is informed, it is considered as `false`.")
|
||||
private Boolean isPublic = true;
|
||||
|
||||
@Parameter(name = ApiConstants.RECURSIVE_DOMAINS, type = CommandType.BOOLEAN, description = "Defines whether the subdomains of the informed domains are considered. Default " +
|
||||
"value is false.")
|
||||
private Boolean recursiveDomains = false;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getCss() {
|
||||
return css;
|
||||
}
|
||||
|
||||
public String getJsonConfiguration() {
|
||||
return jsonConfiguration;
|
||||
}
|
||||
|
||||
public String getCommonNames() {
|
||||
return commonNames;
|
||||
}
|
||||
|
||||
public String getDomainIds() {
|
||||
return domainIds;
|
||||
}
|
||||
|
||||
public String getAccountIds() {
|
||||
return accountIds;
|
||||
}
|
||||
|
||||
public Boolean getPublic() {
|
||||
return isPublic;
|
||||
}
|
||||
|
||||
public Boolean getRecursiveDomains() {
|
||||
return recursiveDomains;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
GuiThemeJoin guiThemeJoin = guiThemeService.createGuiTheme(this);
|
||||
|
||||
if (guiThemeJoin == null) {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create the GUI theme.");
|
||||
}
|
||||
|
||||
GuiThemeResponse response = _responseGenerator.createGuiThemeResponse(guiThemeJoin);
|
||||
response.setResponseName(getCommandName());
|
||||
this.setResponseObject(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
return CallContext.current().getCallingAccountId();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,110 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.user.gui.theme;
|
||||
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseListCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.response.AccountResponse;
|
||||
import org.apache.cloudstack.api.response.DomainResponse;
|
||||
import org.apache.cloudstack.api.response.GuiThemeResponse;
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
import org.apache.cloudstack.gui.theme.GuiTheme;
|
||||
import org.apache.cloudstack.gui.theme.GuiThemeService;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@APICommand(name = "listGuiThemes", description = "Lists GUI themes.", responseObject = GuiThemeResponse.class, entityType = {GuiTheme.class},
|
||||
since = "4.21.0.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin, RoleType.User, RoleType.DomainAdmin,
|
||||
RoleType.ResourceAdmin})
|
||||
public class ListGuiThemesCmd extends BaseListCmd {
|
||||
|
||||
@Inject
|
||||
GuiThemeService guiThemeService;
|
||||
|
||||
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, description = "The theme ID.", entityType = GuiThemeResponse.class)
|
||||
private Long id;
|
||||
|
||||
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "The name of the theme.")
|
||||
private String name;
|
||||
|
||||
@Parameter(name = ApiConstants.COMMON_NAME, type = CommandType.STRING, description = "The internet Common Name (CN) to be filtered.")
|
||||
private String commonName;
|
||||
|
||||
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "The ID of the domain to be filtered.")
|
||||
private Long domainId;
|
||||
|
||||
@Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.UUID, entityType = AccountResponse.class, description = "The ID of the account to be filtered.")
|
||||
private Long accountId;
|
||||
|
||||
@Parameter(name = ApiConstants.LIST_ALL, type = CommandType.BOOLEAN, description = "Whether to list all themes.")
|
||||
private boolean listAll = false;
|
||||
|
||||
@Parameter(name = ApiConstants.SHOW_REMOVED, type = CommandType.BOOLEAN, description = "Whether to list removed themes.")
|
||||
private boolean showRemoved = false;
|
||||
|
||||
@Parameter(name = ApiConstants.SHOW_PUBLIC, type = CommandType.BOOLEAN, description = "Whether to list public themes.")
|
||||
private Boolean showPublic;
|
||||
|
||||
@Parameter(name = ApiConstants.LIST_ONLY_DEFAULT_THEME, type = CommandType.BOOLEAN, description = "Whether to only list the default theme.")
|
||||
private boolean listOnlyDefaultTheme = false;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getCommonName() {
|
||||
return commonName;
|
||||
}
|
||||
|
||||
public Long getDomainId() {
|
||||
return domainId;
|
||||
}
|
||||
|
||||
public Long getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public boolean getListAll() {
|
||||
return listAll;
|
||||
}
|
||||
|
||||
public boolean getShowRemoved() {
|
||||
return showRemoved;
|
||||
}
|
||||
|
||||
public Boolean getShowPublic() {
|
||||
return showPublic;
|
||||
}
|
||||
|
||||
public boolean getListOnlyDefaultTheme() {
|
||||
return listOnlyDefaultTheme;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
ListResponse<GuiThemeResponse> response = guiThemeService.listGuiThemes(this);
|
||||
response.setResponseName(getCommandName());
|
||||
this.setResponseObject(response);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.user.gui.theme;
|
||||
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.response.GuiThemeResponse;
|
||||
import org.apache.cloudstack.api.response.SuccessResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.gui.theme.GuiTheme;
|
||||
import org.apache.cloudstack.gui.theme.GuiThemeService;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@APICommand(name = "removeGuiTheme", description = "Removes an existing GUI theme.", responseObject = GuiThemeResponse.class, entityType = {GuiTheme.class},
|
||||
since = "4.21.0.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin})
|
||||
public class RemoveGuiThemeCmd extends BaseCmd {
|
||||
|
||||
@Inject
|
||||
GuiThemeService guiThemeService;
|
||||
|
||||
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = GuiThemeResponse.class, required = true,
|
||||
description = "The unique identifier of the GUI theme to be removed.")
|
||||
private Long id;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
guiThemeService.removeGuiTheme(this);
|
||||
final SuccessResponse response = new SuccessResponse();
|
||||
response.setResponseName(getCommandName());
|
||||
response.setSuccess(true);
|
||||
setResponseObject(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
return CallContext.current().getCallingAccountId();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,136 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.user.gui.theme;
|
||||
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.GuiThemeResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.gui.theme.GuiTheme;
|
||||
import org.apache.cloudstack.gui.theme.GuiThemeJoin;
|
||||
import org.apache.cloudstack.gui.theme.GuiThemeService;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
|
||||
@APICommand(name = "updateGuiTheme", description = "Updates an existing GUI theme.", responseObject = GuiThemeResponse.class, entityType = {GuiTheme.class},
|
||||
since = "4.21.0.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin})
|
||||
public class UpdateGuiThemeCmd extends BaseCmd {
|
||||
|
||||
@Inject
|
||||
GuiThemeService guiThemeService;
|
||||
|
||||
@Parameter(name = ApiConstants.ID, required = true, type = CommandType.UUID, entityType = GuiThemeResponse.class, description = "The ID of the theme to be updated.")
|
||||
private Long id;
|
||||
|
||||
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, length = 2048, description = "A name to identify the theme.")
|
||||
private String name;
|
||||
|
||||
@Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, length = 4096, description = "A description for the theme.")
|
||||
private String description;
|
||||
|
||||
@Parameter(name = ApiConstants.CSS, type = CommandType.STRING, length = 65535, description = "The CSS to be retrieved and imported into the GUI " +
|
||||
"when matching the theme access configurations.")
|
||||
private String css;
|
||||
|
||||
@Parameter(name = ApiConstants.JSON_CONFIGURATION, type = CommandType.STRING, length = 65535, description = "The JSON with the configurations to be " +
|
||||
"retrieved and imported into the GUI when matching the theme access configurations.")
|
||||
private String jsonConfiguration;
|
||||
|
||||
@Parameter(name = ApiConstants.COMMON_NAMES, type = CommandType.STRING, length = 65535, description = "A set of Common Names (CN) (fixed or " +
|
||||
"wildcard) separated by comma that can retrieve the theme; e.g.: *acme.com,acme2.com")
|
||||
private String commonNames;
|
||||
|
||||
@Parameter(name = ApiConstants.DOMAIN_IDS, type = CommandType.STRING, length = 65535, description = "A set of domain UUIDs (also known as ID for " +
|
||||
"the end-user) separated by comma that can retrieve the theme.")
|
||||
private String domainIds;
|
||||
|
||||
@Parameter(name = ApiConstants.RECURSIVE_DOMAINS, type = CommandType.BOOLEAN, description = "Defines whether the subdomains of the informed domains are considered. Default " +
|
||||
"value is false.")
|
||||
private Boolean recursiveDomains = false;
|
||||
|
||||
@Parameter(name = ApiConstants.ACCOUNT_IDS, type = CommandType.STRING, length = 65535, description = "A set of account UUIDs (also known as ID for" +
|
||||
" the end-user) separated by comma that can retrieve the theme.")
|
||||
private String accountIds;
|
||||
|
||||
@Parameter(name = ApiConstants.IS_PUBLIC, type = CommandType.BOOLEAN, description = "Defines whether a theme can be retrieved by anyone when only " +
|
||||
"the `commonNames` is informed. If the `domainIds` or `accountIds` is informed, it is considered as `false`.")
|
||||
private Boolean isPublic = true;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getCss() {
|
||||
return css;
|
||||
}
|
||||
|
||||
public String getJsonConfiguration() {
|
||||
return jsonConfiguration;
|
||||
}
|
||||
|
||||
public String getCommonNames() {
|
||||
return commonNames;
|
||||
}
|
||||
|
||||
public String getDomainIds() {
|
||||
return domainIds;
|
||||
}
|
||||
|
||||
public String getAccountIds() {
|
||||
return accountIds;
|
||||
}
|
||||
|
||||
public Boolean getRecursiveDomains() {
|
||||
return recursiveDomains;
|
||||
}
|
||||
|
||||
public Boolean getIsPublic() {
|
||||
return isPublic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
GuiThemeJoin guiThemeJoin = guiThemeService.updateGuiTheme(this);
|
||||
|
||||
if (guiThemeJoin == null) {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update the GUI theme.");
|
||||
}
|
||||
|
||||
GuiThemeResponse response = _responseGenerator.createGuiThemeResponse(guiThemeJoin);
|
||||
response.setResponseName(getCommandName());
|
||||
this.setResponseObject(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
return CallContext.current().getCallingAccountId();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,179 @@
|
||||
//Licensed to the Apache Software Foundation (ASF) under one
|
||||
//or more contributor license agreements. See the NOTICE file
|
||||
//distributed with this work for additional information
|
||||
//regarding copyright ownership. The ASF licenses this file
|
||||
//to you under the Apache License, Version 2.0 (the
|
||||
//"License"); you may not use this file except in compliance
|
||||
//with the License. You may obtain a copy of the License at
|
||||
//
|
||||
//http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
//Unless required by applicable law or agreed to in writing,
|
||||
//software distributed under the License is distributed on an
|
||||
//"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
//KIND, either express or implied. See the License for the
|
||||
//specific language governing permissions and limitations
|
||||
//under the License.
|
||||
package org.apache.cloudstack.api.response;
|
||||
|
||||
import com.cloud.serializer.Param;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseResponse;
|
||||
import org.apache.cloudstack.api.EntityReference;
|
||||
import org.apache.cloudstack.gui.theme.GuiThemeJoin;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@EntityReference(value = {GuiThemeJoin.class})
|
||||
public class GuiThemeResponse extends BaseResponse {
|
||||
|
||||
@SerializedName(ApiConstants.ID)
|
||||
@Param(description = "ID of the custom GUI theme.")
|
||||
private String id;
|
||||
|
||||
@SerializedName(ApiConstants.NAME)
|
||||
@Param(description = "Name of the GUI theme.")
|
||||
private String name;
|
||||
|
||||
@SerializedName(ApiConstants.DESCRIPTION)
|
||||
@Param(description = "Description of the GUI theme.")
|
||||
private String description;
|
||||
|
||||
@SerializedName(ApiConstants.CSS)
|
||||
@Param(description = "The CSS to be retrieved and imported into the GUI when matching the theme access configurations.")
|
||||
private String css;
|
||||
|
||||
@SerializedName(ApiConstants.JSON_CONFIGURATION)
|
||||
@Param(description = "The JSON with the configurations to be retrieved and imported into the GUI when matching the theme access configurations.")
|
||||
private String jsonConfiguration;
|
||||
|
||||
@SerializedName(ApiConstants.COMMON_NAMES)
|
||||
@Param(description = "A set of Common Names (CN) (fixed or wildcard) separated by comma that can retrieve the theme; e.g.: *acme.com,acme2.com")
|
||||
private String commonNames;
|
||||
|
||||
@SerializedName(ApiConstants.DOMAIN_IDS)
|
||||
@Param(description = "A set of domain UUIDs (also known as ID for the end-user) separated by comma that can retrieve the theme.")
|
||||
private String domainIds;
|
||||
|
||||
@SerializedName(ApiConstants.RECURSIVE_DOMAINS)
|
||||
@Param(description = "Whether to consider the subdomains of the informed domain IDs.")
|
||||
private Boolean recursiveDomains;
|
||||
|
||||
@SerializedName(ApiConstants.ACCOUNT_IDS)
|
||||
@Param(description = "A set of account UUIDs (also known as ID for the end-user) separated by comma that can retrieve the theme.")
|
||||
private String accountIds;
|
||||
|
||||
@SerializedName(ApiConstants.IS_PUBLIC)
|
||||
@Param(description = "Defines whether a theme can be retrieved by anyone when only the `commonNames` is informed. If the `domainIds` or `accountIds` is informed, it is " +
|
||||
"considered as `false`.")
|
||||
private Boolean isPublic;
|
||||
|
||||
@SerializedName(ApiConstants.CREATED)
|
||||
@Param(description = "When the GUI theme was created.")
|
||||
private Date created;
|
||||
|
||||
@SerializedName(ApiConstants.REMOVED)
|
||||
@Param(description = "When the GUI theme was removed.")
|
||||
private Date removed;
|
||||
|
||||
public GuiThemeResponse() {
|
||||
super("guiThemes");
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getCss() {
|
||||
return css;
|
||||
}
|
||||
|
||||
public void setCss(String css) {
|
||||
this.css = css;
|
||||
}
|
||||
|
||||
public String getJsonConfiguration() {
|
||||
return jsonConfiguration;
|
||||
}
|
||||
|
||||
public void setJsonConfiguration(String jsonConfiguration) {
|
||||
this.jsonConfiguration = jsonConfiguration;
|
||||
}
|
||||
|
||||
public String getCommonNames() {
|
||||
return commonNames;
|
||||
}
|
||||
|
||||
public void setCommonNames(String commonNames) {
|
||||
this.commonNames = commonNames;
|
||||
}
|
||||
|
||||
public String getDomainIds() {
|
||||
return domainIds;
|
||||
}
|
||||
|
||||
public void setDomainIds(String domainIds) {
|
||||
this.domainIds = domainIds;
|
||||
}
|
||||
|
||||
public String getAccountIds() {
|
||||
return accountIds;
|
||||
}
|
||||
|
||||
public void setAccountIds(String accountIds) {
|
||||
this.accountIds = accountIds;
|
||||
}
|
||||
|
||||
public Boolean getPublic() {
|
||||
return isPublic;
|
||||
}
|
||||
|
||||
public void setPublic(Boolean aPublic) {
|
||||
isPublic = aPublic;
|
||||
}
|
||||
|
||||
public Date getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
public void setCreated(Date created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
public Date getRemoved() {
|
||||
return removed;
|
||||
}
|
||||
|
||||
public Boolean getRecursiveDomains() {
|
||||
return recursiveDomains;
|
||||
}
|
||||
|
||||
public void setRecursiveDomains(Boolean recursiveDomains) {
|
||||
this.recursiveDomains = recursiveDomains;
|
||||
}
|
||||
|
||||
public void setRemoved(Date removed) {
|
||||
this.removed = removed;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.gui.theme;
|
||||
|
||||
import org.apache.cloudstack.api.Identity;
|
||||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public interface GuiTheme extends InternalIdentity, Identity {
|
||||
|
||||
String getName();
|
||||
|
||||
String getDescription();
|
||||
|
||||
String getCss();
|
||||
|
||||
String getJsonConfiguration();
|
||||
|
||||
Date getCreated();
|
||||
|
||||
Date getRemoved();
|
||||
|
||||
boolean getIsPublic();
|
||||
|
||||
void setId(Long id);
|
||||
|
||||
void setUuid(String uuid);
|
||||
|
||||
void setName(String name);
|
||||
|
||||
void setDescription(String description);
|
||||
|
||||
void setCss(String css);
|
||||
|
||||
void setJsonConfiguration(String jsonConfiguration);
|
||||
|
||||
void setCreated(Date created);
|
||||
|
||||
void setRemoved(Date removed);
|
||||
|
||||
void setIsPublic(boolean isPublic);
|
||||
|
||||
boolean isRecursiveDomains();
|
||||
|
||||
void setRecursiveDomains(boolean recursiveDomains);
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.gui.theme;
|
||||
|
||||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
|
||||
public interface GuiThemeDetails extends InternalIdentity {
|
||||
|
||||
void setId(Long id);
|
||||
|
||||
Long getGuiThemeId();
|
||||
|
||||
void setGuiThemeId(Long guiThemeId);
|
||||
|
||||
String getType();
|
||||
|
||||
void setType(String type);
|
||||
|
||||
String getValue();
|
||||
|
||||
void setValue(String value);
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.gui.theme;
|
||||
|
||||
import org.apache.cloudstack.api.Identity;
|
||||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public interface GuiThemeJoin extends InternalIdentity, Identity {
|
||||
|
||||
String getName();
|
||||
|
||||
String getDescription();
|
||||
|
||||
String getCss();
|
||||
|
||||
String getJsonConfiguration();
|
||||
|
||||
String getCommonNames();
|
||||
|
||||
String getDomains();
|
||||
|
||||
String getAccounts();
|
||||
|
||||
boolean isRecursiveDomains();
|
||||
|
||||
boolean getIsPublic();
|
||||
|
||||
Date getCreated();
|
||||
|
||||
Date getRemoved();
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.gui.theme;
|
||||
|
||||
import org.apache.cloudstack.api.command.user.gui.theme.CreateGuiThemeCmd;
|
||||
import org.apache.cloudstack.api.command.user.gui.theme.ListGuiThemesCmd;
|
||||
import org.apache.cloudstack.api.command.user.gui.theme.RemoveGuiThemeCmd;
|
||||
import org.apache.cloudstack.api.command.user.gui.theme.UpdateGuiThemeCmd;
|
||||
import org.apache.cloudstack.api.response.GuiThemeResponse;
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
|
||||
public interface GuiThemeService {
|
||||
|
||||
ListResponse<GuiThemeResponse> listGuiThemes(ListGuiThemesCmd cmd);
|
||||
|
||||
GuiThemeJoin createGuiTheme(CreateGuiThemeCmd cmd);
|
||||
|
||||
GuiThemeJoin updateGuiTheme(UpdateGuiThemeCmd cmd);
|
||||
|
||||
void removeGuiTheme(RemoveGuiThemeCmd cmd);
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.gui.theme;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "gui_themes_details")
|
||||
public class GuiThemeDetailsVO implements GuiThemeDetails {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id", nullable = false)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "gui_theme_id", nullable = false)
|
||||
private Long guiThemeId;
|
||||
|
||||
@Column(name = "type", nullable = false, length = 100)
|
||||
private String type;
|
||||
|
||||
@Column(name = "value", nullable = false, length = 65535)
|
||||
private String value;
|
||||
|
||||
public GuiThemeDetailsVO() {
|
||||
}
|
||||
|
||||
public GuiThemeDetailsVO(Long guiThemeId, String type, String value) {
|
||||
this.guiThemeId = guiThemeId;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getGuiThemeId() {
|
||||
return guiThemeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGuiThemeId(Long guiThemeId) {
|
||||
this.guiThemeId = guiThemeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,141 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.gui.theme;
|
||||
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import java.util.Date;
|
||||
|
||||
@Entity
|
||||
@Table(name = "gui_themes_view")
|
||||
public class GuiThemeJoinVO implements GuiThemeJoin {
|
||||
@Id
|
||||
@Column(name = "id", nullable = false)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "uuid", nullable = false)
|
||||
private String uuid;
|
||||
|
||||
@Column(name = "name", nullable = false, length = 2048)
|
||||
private String name;
|
||||
|
||||
@Column(name = "description", length = 4096)
|
||||
private String description;
|
||||
|
||||
@Column(name = "css", nullable = false, length = 65535)
|
||||
private String css;
|
||||
|
||||
@Column(name = "json_configuration", nullable = false, length = 65535)
|
||||
private String jsonConfiguration;
|
||||
|
||||
@Column(name = "common_names", length = 65535)
|
||||
private String commonNames;
|
||||
|
||||
@Column(name = "domains", length = 65535)
|
||||
private String domains;
|
||||
|
||||
@Column(name = "accounts", length = 65535)
|
||||
private String accounts;
|
||||
|
||||
@Column(name = "recursive_domains")
|
||||
private boolean recursiveDomains;
|
||||
|
||||
@Column(name = "is_public")
|
||||
private boolean isPublic;
|
||||
|
||||
@Column(name = GenericDao.CREATED_COLUMN, nullable = false)
|
||||
@Temporal(value = TemporalType.TIMESTAMP)
|
||||
private Date created;
|
||||
|
||||
@Column(name = GenericDao.REMOVED_COLUMN)
|
||||
@Temporal(value = TemporalType.TIMESTAMP)
|
||||
private Date removed = null;
|
||||
|
||||
public GuiThemeJoinVO() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCss() {
|
||||
return css;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJsonConfiguration() {
|
||||
return jsonConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommonNames() {
|
||||
return commonNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDomains() {
|
||||
return domains;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccounts() {
|
||||
return accounts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRecursiveDomains() {
|
||||
return recursiveDomains;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getIsPublic() {
|
||||
return isPublic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getRemoved() {
|
||||
return removed;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,189 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.gui.theme;
|
||||
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "gui_themes")
|
||||
public class GuiThemeVO implements GuiTheme {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id", nullable = false)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "uuid", nullable = false)
|
||||
private String uuid = UUID.randomUUID().toString();
|
||||
|
||||
@Column(name = "name", nullable = false, length = 2048)
|
||||
private String name;
|
||||
|
||||
@Column(name = "description", length = 4096)
|
||||
private String description;
|
||||
|
||||
@Column(name = "css", length = 65535)
|
||||
private String css;
|
||||
|
||||
@Column(name = "json_configuration", length = 65535)
|
||||
private String jsonConfiguration;
|
||||
|
||||
@Column(name = "is_public")
|
||||
private boolean isPublic;
|
||||
|
||||
@Column(name = "recursive_domains")
|
||||
private boolean recursiveDomains = false;
|
||||
|
||||
@Column(name = GenericDao.CREATED_COLUMN, nullable = false)
|
||||
@Temporal(value = TemporalType.TIMESTAMP)
|
||||
private Date created;
|
||||
|
||||
@Column(name = GenericDao.REMOVED_COLUMN)
|
||||
@Temporal(value = TemporalType.TIMESTAMP)
|
||||
private Date removed = null;
|
||||
|
||||
public GuiThemeVO() {
|
||||
|
||||
}
|
||||
|
||||
public GuiThemeVO(String name, String description, String css, String jsonConfiguration, boolean recursiveDomains, boolean isPublic, Date created, Date removed) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.css = css;
|
||||
this.jsonConfiguration = jsonConfiguration;
|
||||
this.recursiveDomains = recursiveDomains;
|
||||
this.isPublic = isPublic;
|
||||
this.created = created;
|
||||
this.removed = removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCss() {
|
||||
return css;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJsonConfiguration() {
|
||||
return jsonConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getRemoved() {
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getIsPublic() {
|
||||
return isPublic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUuid(String uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCss(String css) {
|
||||
this.css = css;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setJsonConfiguration(String jsonConfiguration) {
|
||||
this.jsonConfiguration = jsonConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreated(Date created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRemoved(Date removed) {
|
||||
this.removed = removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIsPublic(boolean isPublic) {
|
||||
this.isPublic = isPublic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRecursiveDomains() {
|
||||
return recursiveDomains;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecursiveDomains(boolean recursiveDomains) {
|
||||
this.recursiveDomains = recursiveDomains;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "uuid", "name", "description", "isPublic", "recursiveDomains");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.gui.theme.dao;
|
||||
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
import org.apache.cloudstack.gui.theme.GuiThemeVO;
|
||||
|
||||
public interface GuiThemeDao extends GenericDao<GuiThemeVO, Long> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.gui.theme.dao;
|
||||
|
||||
import com.cloud.utils.db.GenericDaoBase;
|
||||
import org.apache.cloudstack.gui.theme.GuiThemeVO;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class GuiThemeDaoImpl extends GenericDaoBase<GuiThemeVO, Long> implements GuiThemeDao {
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.gui.theme.dao;
|
||||
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
import org.apache.cloudstack.gui.theme.GuiThemeDetailsVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface GuiThemeDetailsDao extends GenericDao<GuiThemeDetailsVO, Long> {
|
||||
List<Long> listGuiThemeIdsByCommonName(String commonName);
|
||||
|
||||
List<Long> listGuiThemeIdsByDomainUuids(String domainUuid);
|
||||
|
||||
void expungeByGuiThemeId(long guiThemeId);
|
||||
}
|
||||
@ -0,0 +1,126 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.gui.theme.dao;
|
||||
|
||||
import com.cloud.domain.DomainVO;
|
||||
import com.cloud.domain.dao.DomainDao;
|
||||
import com.cloud.utils.db.GenericDaoBase;
|
||||
import com.cloud.utils.db.GenericSearchBuilder;
|
||||
import com.cloud.utils.db.JoinBuilder;
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
import org.apache.cloudstack.gui.theme.GuiThemeDetailsVO;
|
||||
import org.apache.cloudstack.gui.theme.GuiThemeVO;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class GuiThemeDetailsDaoImpl extends GenericDaoBase<GuiThemeDetailsVO, Long> implements GuiThemeDetailsDao {
|
||||
|
||||
@Inject
|
||||
DomainDao domainDao;
|
||||
|
||||
@Inject
|
||||
GuiThemeDao guiThemeDao;
|
||||
|
||||
public List<Long> listGuiThemeIdsByCommonName(String commonName) {
|
||||
GenericSearchBuilder<GuiThemeDetailsVO, Long> detailsDaoSearchBuilder = createSearchBuilder(Long.class);
|
||||
detailsDaoSearchBuilder.selectFields(detailsDaoSearchBuilder.entity().getGuiThemeId());
|
||||
detailsDaoSearchBuilder.and("commonNameType", detailsDaoSearchBuilder.entity().getType(), SearchCriteria.Op.EQ);
|
||||
detailsDaoSearchBuilder.and().op("firstReplace", detailsDaoSearchBuilder.entity().getValue(), SearchCriteria.Op.LIKE_REPLACE);
|
||||
detailsDaoSearchBuilder.or("secondReplace", detailsDaoSearchBuilder.entity().getValue(), SearchCriteria.Op.LIKE_REPLACE).cp();
|
||||
detailsDaoSearchBuilder.done();
|
||||
|
||||
SearchCriteria<Long> searchCriteria = detailsDaoSearchBuilder.create();
|
||||
searchCriteria.setParameters("commonNameType", "commonName");
|
||||
searchCriteria.setParameters("firstReplace", commonName, "*", "%");
|
||||
searchCriteria.setParameters("secondReplace", commonName, "*.", "%");
|
||||
|
||||
return customSearch(searchCriteria, null);
|
||||
}
|
||||
|
||||
public List<Long> listGuiThemeIdsByDomainUuids(String domainUuid) {
|
||||
List<Long> guiThemeIds = new ArrayList<>();
|
||||
String requestedDomainPath = domainDao.findByUuid(domainUuid).getPath();
|
||||
|
||||
SearchBuilder<DomainVO> domainSearchBuilderPathLike = domainDao.createSearchBuilder();
|
||||
domainSearchBuilderPathLike.and("pathLike", domainSearchBuilderPathLike.entity().getPath(), SearchCriteria.Op.LIKE_CONCAT);
|
||||
|
||||
SearchBuilder<DomainVO> domainSearchBuilderPathEq = domainDao.createSearchBuilder();
|
||||
domainSearchBuilderPathEq.and("pathEq", domainSearchBuilderPathEq.entity().getPath(), SearchCriteria.Op.EQ);
|
||||
|
||||
GenericSearchBuilder<GuiThemeDetailsVO, Long> detailsSearchBuilderPathLike = createDetailsSearchBuilder(domainSearchBuilderPathLike);
|
||||
SearchCriteria<Long> searchCriteriaDomainPathLike = setParametersDomainPathLike(detailsSearchBuilderPathLike, requestedDomainPath);
|
||||
|
||||
GenericSearchBuilder<GuiThemeDetailsVO, Long> detailsSearchBuilderPathEq = createDetailsSearchBuilder(domainSearchBuilderPathEq);
|
||||
SearchCriteria<Long> searchCriteriaDomainPathEq = setParametersDomainPathEq(detailsSearchBuilderPathEq, requestedDomainPath);
|
||||
|
||||
guiThemeIds.addAll(customSearch(searchCriteriaDomainPathLike, null));
|
||||
guiThemeIds.addAll(customSearch(searchCriteriaDomainPathEq, null));
|
||||
return guiThemeIds;
|
||||
}
|
||||
|
||||
private SearchCriteria<Long> setParametersDomainPathLike(GenericSearchBuilder<GuiThemeDetailsVO, Long> detailsSearchBuilderPathLike, String requestedDomainPath) {
|
||||
SearchCriteria<Long> searchCriteria = detailsSearchBuilderPathLike.create();
|
||||
searchCriteria.setParameters("domainUuidType", "domain");
|
||||
searchCriteria.setJoinParameters("domainJoin", "pathLike", requestedDomainPath, "%");
|
||||
searchCriteria.setJoinParameters("guiThemesJoin", "recursiveDomains", true);
|
||||
|
||||
return searchCriteria;
|
||||
}
|
||||
|
||||
private SearchCriteria<Long> setParametersDomainPathEq(GenericSearchBuilder<GuiThemeDetailsVO, Long> detailsSearchBuilderPathEq, String requestedDomainPath) {
|
||||
SearchCriteria<Long> searchCriteria = detailsSearchBuilderPathEq.create();
|
||||
searchCriteria.setParameters("domainUuidType", "domain");
|
||||
searchCriteria.setJoinParameters("domainJoin", "pathEq", requestedDomainPath);
|
||||
searchCriteria.setJoinParameters("guiThemesJoin", "recursiveDomains", false);
|
||||
|
||||
return searchCriteria;
|
||||
}
|
||||
|
||||
private GenericSearchBuilder<GuiThemeDetailsVO, Long> createDetailsSearchBuilder(SearchBuilder<DomainVO> domainSearchBuilder) {
|
||||
SearchBuilder<GuiThemeVO> guiThemeDaoSearchBuilder = guiThemeDao.createSearchBuilder();
|
||||
guiThemeDaoSearchBuilder.and("recursiveDomains", guiThemeDaoSearchBuilder.entity().isRecursiveDomains(), SearchCriteria.Op.EQ);
|
||||
|
||||
GenericSearchBuilder<GuiThemeDetailsVO, Long> guiThemesDetailsJoinDomainJoinGuiThemesSearchBuilder = createSearchBuilder(Long.class);
|
||||
guiThemesDetailsJoinDomainJoinGuiThemesSearchBuilder.selectFields(guiThemesDetailsJoinDomainJoinGuiThemesSearchBuilder.entity().getGuiThemeId());
|
||||
guiThemesDetailsJoinDomainJoinGuiThemesSearchBuilder.and("domainUuidType", guiThemesDetailsJoinDomainJoinGuiThemesSearchBuilder.entity().getType(), SearchCriteria.Op.EQ);
|
||||
guiThemesDetailsJoinDomainJoinGuiThemesSearchBuilder.join("domainJoin", domainSearchBuilder, domainSearchBuilder.entity().getUuid(),
|
||||
guiThemesDetailsJoinDomainJoinGuiThemesSearchBuilder.entity().getValue(), JoinBuilder.JoinType.INNER);
|
||||
guiThemesDetailsJoinDomainJoinGuiThemesSearchBuilder.join("guiThemesJoin", guiThemeDaoSearchBuilder, guiThemeDaoSearchBuilder.entity().getId(),
|
||||
guiThemesDetailsJoinDomainJoinGuiThemesSearchBuilder.entity().getGuiThemeId(), JoinBuilder.JoinType.INNER);
|
||||
|
||||
domainSearchBuilder.done();
|
||||
guiThemeDaoSearchBuilder.done();
|
||||
guiThemesDetailsJoinDomainJoinGuiThemesSearchBuilder.done();
|
||||
|
||||
return guiThemesDetailsJoinDomainJoinGuiThemesSearchBuilder;
|
||||
}
|
||||
|
||||
public void expungeByGuiThemeId(long guiThemeId) {
|
||||
SearchBuilder<GuiThemeDetailsVO> searchBuilder = createSearchBuilder();
|
||||
searchBuilder.and("guiThemeId", searchBuilder.entity().getGuiThemeId(), SearchCriteria.Op.EQ);
|
||||
searchBuilder.done();
|
||||
|
||||
SearchCriteria<GuiThemeDetailsVO> searchCriteria = searchBuilder.create();
|
||||
searchCriteria.setParameters("guiThemeId", guiThemeId);
|
||||
expunge(searchCriteria);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.gui.theme.dao;
|
||||
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
import org.apache.cloudstack.gui.theme.GuiThemeJoinVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface GuiThemeJoinDao extends GenericDao<GuiThemeJoinVO, Long> {
|
||||
GuiThemeJoinVO findDefaultTheme();
|
||||
|
||||
Pair<List<GuiThemeJoinVO>, Integer> listGuiThemesWithNoAuthentication(String commonName);
|
||||
|
||||
Pair<List<GuiThemeJoinVO>, Integer> listGuiThemes(Long id, String name, String commonName, String domainUuid, String accountUuid, boolean listAll, boolean showRemoved, Boolean showPublic);
|
||||
}
|
||||
@ -0,0 +1,139 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.gui.theme.dao;
|
||||
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.db.Filter;
|
||||
import com.cloud.utils.db.GenericDaoBase;
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.gui.theme.GuiThemeJoinVO;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class GuiThemeJoinDaoImpl extends GenericDaoBase<GuiThemeJoinVO, Long> implements GuiThemeJoinDao {
|
||||
@Inject
|
||||
GuiThemeDetailsDao guiThemeDetailsDao;
|
||||
|
||||
public static final Long INVALID_ID = -1L;
|
||||
|
||||
public GuiThemeJoinVO findDefaultTheme() {
|
||||
SearchBuilder<GuiThemeJoinVO> searchBuilder = createSearchBuilder();
|
||||
searchBuilder.and("commonNames", searchBuilder.entity().getCommonNames(), SearchCriteria.Op.NULL);
|
||||
searchBuilder.and("domainUuids", searchBuilder.entity().getDomains(), SearchCriteria.Op.NULL);
|
||||
searchBuilder.and("accountUuids", searchBuilder.entity().getAccounts(), SearchCriteria.Op.NULL);
|
||||
searchBuilder.done();
|
||||
|
||||
SearchCriteria<GuiThemeJoinVO> searchCriteria = searchBuilder.create();
|
||||
|
||||
return findOneBy(searchCriteria);
|
||||
}
|
||||
|
||||
public Pair<List<GuiThemeJoinVO>, Integer> listGuiThemesWithNoAuthentication(String commonName) {
|
||||
SearchCriteria<GuiThemeJoinVO> searchCriteria = createGuiThemeSearchCriteria(null, null, commonName, null, null, null, false);
|
||||
return searchOrderByCreatedDate(searchCriteria, false);
|
||||
}
|
||||
|
||||
public Pair<List<GuiThemeJoinVO>, Integer> listGuiThemes(Long id, String name, String commonName, String domainUuid, String accountUuid, boolean listAll,
|
||||
boolean showRemoved, Boolean showPublic) {
|
||||
SearchCriteria<GuiThemeJoinVO> searchCriteria = createGuiThemeSearchCriteria(id, name, commonName, domainUuid, accountUuid, showPublic, listAll);
|
||||
|
||||
if (listAll) {
|
||||
showRemoved = false;
|
||||
}
|
||||
|
||||
return searchOrderByCreatedDate(searchCriteria, showRemoved);
|
||||
}
|
||||
|
||||
private Pair<List<GuiThemeJoinVO>, Integer> searchOrderByCreatedDate(SearchCriteria<GuiThemeJoinVO> searchCriteria, boolean showRemoved) {
|
||||
Filter filter = new Filter(GuiThemeJoinVO.class, "created", false);
|
||||
return searchAndCount(searchCriteria, filter, showRemoved);
|
||||
}
|
||||
|
||||
private SearchCriteria<GuiThemeJoinVO> createGuiThemeSearchCriteria(Long id, String name, String commonName, String domainUuid, String accountUuid, Boolean showPublic, boolean listAll) {
|
||||
SearchCriteria<GuiThemeJoinVO> searchCriteria = createGuiThemeJoinSearchBuilder(listAll, showPublic).create();
|
||||
List<Long> idList = new ArrayList<>();
|
||||
|
||||
if (id != null) {
|
||||
idList.add(id);
|
||||
}
|
||||
|
||||
searchCriteria.setParametersIfNotNull("name", name);
|
||||
searchCriteria.setParametersIfNotNull("isPublic", showPublic);
|
||||
|
||||
if (StringUtils.isNotBlank(accountUuid)) {
|
||||
searchCriteria.setParameters("accountUuid", "%" + accountUuid + "%");
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(commonName)) {
|
||||
setGuiThemeIdsFilteredByType(idList, ApiConstants.COMMON_NAME, commonName);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(domainUuid)) {
|
||||
setGuiThemeIdsFilteredByType(idList, ApiConstants.DOMAIN, domainUuid);
|
||||
}
|
||||
|
||||
searchCriteria.setParametersIfNotNull("idIn", idList.toArray());
|
||||
|
||||
return searchCriteria;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the `id IN ( )` clause of the query. If the informed value of common name or domain ID does not retrieve any GUI theme ID; then, an invalid ID (-1) is passed to the
|
||||
* list, as not a single entity has this ID. This is necessary as to set the parameter even if it did not find any GUI theme ID; otherwise, the query would not filter the
|
||||
* common name or domain ID passed.
|
||||
*/
|
||||
public void setGuiThemeIdsFilteredByType(List<Long> idList, String type, String value) {
|
||||
List<Long> guiThemeIdsFilteredByType = new ArrayList<>();
|
||||
|
||||
switch (type) {
|
||||
case ApiConstants.COMMON_NAME:
|
||||
guiThemeIdsFilteredByType = guiThemeDetailsDao.listGuiThemeIdsByCommonName(value);
|
||||
break;
|
||||
case ApiConstants.DOMAIN:
|
||||
guiThemeIdsFilteredByType = guiThemeDetailsDao.listGuiThemeIdsByDomainUuids(value);
|
||||
break;
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(guiThemeIdsFilteredByType)) {
|
||||
idList.addAll(guiThemeIdsFilteredByType);
|
||||
return;
|
||||
}
|
||||
logger.trace(String.format("No GUI theme with the specified [%s] with UUID [%s] was found, adding an invalid ID for filtering.", type, value));
|
||||
idList.add(INVALID_ID);
|
||||
}
|
||||
|
||||
private SearchBuilder<GuiThemeJoinVO> createGuiThemeJoinSearchBuilder(boolean listAll, Boolean showPublic) {
|
||||
SearchBuilder<GuiThemeJoinVO> guiThemeJoinSearchBuilder = createSearchBuilder();
|
||||
guiThemeJoinSearchBuilder.and("idIn", guiThemeJoinSearchBuilder.entity().getId(), SearchCriteria.Op.IN);
|
||||
guiThemeJoinSearchBuilder.and("name", guiThemeJoinSearchBuilder.entity().getName(), SearchCriteria.Op.EQ);
|
||||
guiThemeJoinSearchBuilder.and("accountUuid", guiThemeJoinSearchBuilder.entity().getAccounts(), SearchCriteria.Op.LIKE);
|
||||
|
||||
if (!listAll && showPublic != null) {
|
||||
guiThemeJoinSearchBuilder.and("isPublic", guiThemeJoinSearchBuilder.entity().getIsPublic(), SearchCriteria.Op.EQ);
|
||||
}
|
||||
|
||||
return guiThemeJoinSearchBuilder;
|
||||
}
|
||||
}
|
||||
@ -301,4 +301,7 @@
|
||||
<bean id="SharedFSDaoImpl" class="org.apache.cloudstack.storage.sharedfs.dao.SharedFSDaoImpl" />
|
||||
<bean id="SharedFSJoinDaoImpl" class="org.apache.cloudstack.storage.sharedfs.query.dao.SharedFSJoinDaoImpl" />
|
||||
<bean id="ReconcileCommandDaoImpl" class="org.apache.cloudstack.command.dao.ReconcileCommandDaoImpl" />
|
||||
<bean id="guiThemeDaoImpl" class="org.apache.cloudstack.gui.theme.dao.GuiThemeDaoImpl" />
|
||||
<bean id="guiThemeDetailsDaoImpl" class="org.apache.cloudstack.gui.theme.dao.GuiThemeDetailsDaoImpl" />
|
||||
<bean id="guiThemeJoinDaoImpl" class="org.apache.cloudstack.gui.theme.dao.GuiThemeJoinDaoImpl" />
|
||||
</beans>
|
||||
|
||||
@ -203,3 +203,27 @@ SET `sort_key` = CASE
|
||||
ELSE `sort_key`
|
||||
END;
|
||||
-- End: Changes for Guest OS category cleanup
|
||||
|
||||
-- Whitelabel GUI
|
||||
CREATE TABLE IF NOT EXISTS `cloud`.`gui_themes` (
|
||||
`id` bigint(20) unsigned NOT NULL auto_increment,
|
||||
`uuid` varchar(255) UNIQUE,
|
||||
`name` varchar(2048) NOT NULL COMMENT 'A name to identify the theme.',
|
||||
`description` varchar(4096) DEFAULT NULL COMMENT 'A description for the theme.',
|
||||
`css` text DEFAULT NULL COMMENT 'The CSS to be retrieved and imported into the GUI when matching the theme access configurations.',
|
||||
`json_configuration` text DEFAULT NULL COMMENT 'The JSON with the configurations to be retrieved and imported into the GUI when matching the theme access configurations.',
|
||||
`recursive_domains` tinyint(1) DEFAULT 0 COMMENT 'Defines whether the subdomains of the informed domains are considered. Default value is false.',
|
||||
`is_public` tinyint(1) default 1 COMMENT 'Defines whether a theme can be retrieved by anyone when only the `internet_domains_names` is informed. If the `domain_uuids` or `account_uuids` is informed, it is considered as `false`.',
|
||||
`created` datetime NOT NULL,
|
||||
`removed` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `cloud`.`gui_themes_details` (
|
||||
`id` bigint(20) unsigned NOT NULL auto_increment,
|
||||
`gui_theme_id` bigint(20) unsigned NOT NULL COMMENT 'Foreign key referencing the GUI theme on `gui_themes` table.',
|
||||
`type` varchar(100) NOT NULL COMMENT 'The type of GUI theme details. Valid options are: `account`, `domain` and `commonName`',
|
||||
`value` text NOT NULL COMMENT 'The value of the `type` details. Can be an UUID (account or domain) or internet common name.',
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `fk_gui_themes_details__gui_theme_id` FOREIGN KEY (`gui_theme_id`) REFERENCES `gui_themes`(`id`)
|
||||
);
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
-- Licensed to the Apache Software Foundation (ASF) under one
|
||||
-- or more contributor license agreements. See the NOTICE file
|
||||
-- distributed with this work for additional information
|
||||
-- regarding copyright ownership. The ASF licenses this file
|
||||
-- to you under the Apache License, Version 2.0 (the
|
||||
-- "License"); you may not use this file except in compliance
|
||||
-- with the License. You may obtain a copy of the License at
|
||||
--
|
||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
||||
--
|
||||
-- Unless required by applicable law or agreed to in writing,
|
||||
-- software distributed under the License is distributed on an
|
||||
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
-- KIND, either express or implied. See the License for the
|
||||
-- specific language governing permissions and limitations
|
||||
-- under the License.
|
||||
|
||||
-- VIEW `cloud`.`gui_themes_view`;
|
||||
|
||||
DROP VIEW IF EXISTS `cloud`.`gui_themes_view`;
|
||||
|
||||
CREATE VIEW `cloud`.`gui_themes_view` AS
|
||||
SELECT
|
||||
`cloud`.`gui_themes`.`id` AS `id`,
|
||||
`cloud`.`gui_themes`.`uuid` AS `uuid`,
|
||||
`cloud`.`gui_themes`.`name` AS `name`,
|
||||
`cloud`.`gui_themes`.`description` AS `description`,
|
||||
`cloud`.`gui_themes`.`css` AS `css`,
|
||||
`cloud`.`gui_themes`.`json_configuration` AS `json_configuration`,
|
||||
(SELECT group_concat(gtd.`value` separator ',') FROM `cloud`.`gui_themes_details` gtd WHERE gtd.`type` = 'commonName' AND gtd.gui_theme_id = `cloud`.`gui_themes`.`id`) common_names,
|
||||
(SELECT group_concat(gtd.`value` separator ',') FROM `cloud`.`gui_themes_details` gtd WHERE gtd.`type` = 'domain' AND gtd.gui_theme_id = `cloud`.`gui_themes`.`id`) domains,
|
||||
(SELECT group_concat(gtd.`value` separator ',') FROM `cloud`.`gui_themes_details` gtd WHERE gtd.`type` = 'account' AND gtd.gui_theme_id = `cloud`.`gui_themes`.`id`) accounts,
|
||||
`cloud`.`gui_themes`.`recursive_domains` AS `recursive_domains`,
|
||||
`cloud`.`gui_themes`.`is_public` AS `is_public`,
|
||||
`cloud`.`gui_themes`.`created` AS `created`,
|
||||
`cloud`.`gui_themes`.`removed` AS `removed`
|
||||
FROM `cloud`.`gui_themes` LEFT JOIN `cloud`.`gui_themes_details` ON `cloud`.`gui_themes_details`.`gui_theme_id` = `cloud`.`gui_themes`.`id`
|
||||
GROUP BY `cloud`.`gui_themes`.`id`;
|
||||
@ -479,6 +479,14 @@ public abstract class SearchBase<J extends SearchBase<?, T, K>, T, K> {
|
||||
sql.append(" FIND_IN_SET(?, ");
|
||||
}
|
||||
|
||||
if (op == Op.LIKE_REPLACE) {
|
||||
sql.append(" ? LIKE REPLACE (");
|
||||
}
|
||||
|
||||
if (op == Op.LIKE_CONCAT) {
|
||||
sql.append(" ? LIKE CONCAT (");
|
||||
}
|
||||
|
||||
if (tableAlias == null) {
|
||||
if (joinName != null) {
|
||||
tableAlias = joinName;
|
||||
|
||||
@ -39,7 +39,8 @@ public class SearchCriteria<K> {
|
||||
" NOT BETWEEN ? AND ? ",
|
||||
2), IN(" IN () ", -1), NOTIN(" NOT IN () ", -1), LIKE(" LIKE ? ", 1), NLIKE(" NOT LIKE ? ", 1), NIN(" NOT IN () ", -1), NULL(" IS NULL ", 0), NNULL(
|
||||
" IS NOT NULL ",
|
||||
0), SC(" () ", 1), TEXT(" () ", 1), RP("", 0), AND(" AND ", 0), OR(" OR ", 0), NOT(" NOT ", 0), FIND_IN_SET(" ) ", 1), BINARY_OR(" & ?) > 0", 1);
|
||||
0), SC(" () ", 1), TEXT(" () ", 1), RP("", 0), AND(" AND ", 0), OR(" OR ", 0), NOT(" NOT ", 0), FIND_IN_SET(" ) ", 1), BINARY_OR(" & ?) > 0", 1),
|
||||
LIKE_REPLACE(", ?, ?)", 3), LIKE_CONCAT(", ?)", 2);
|
||||
|
||||
private final String op;
|
||||
int params;
|
||||
@ -60,7 +61,8 @@ public class SearchCriteria<K> {
|
||||
}
|
||||
|
||||
public enum Func {
|
||||
NATIVE("@", 1), MAX("MAX(@)", 1), MIN("MIN(@)", 1), FIRST("FIRST(@)", 1), LAST("LAST(@)", 1), SUM("SUM(@)", 1), COUNT("COUNT(@)", 1), DISTINCT("DISTINCT(@)", 1), DISTINCT_PAIR("DISTINCT @, @", 2);
|
||||
NATIVE("@", 1), MAX("MAX(@)", 1), MIN("MIN(@)", 1), FIRST("FIRST(@)", 1), LAST("LAST(@)", 1), SUM("SUM(@)", 1), COUNT("COUNT(@)", 1), DISTINCT("DISTINCT(@)", 1), DISTINCT_PAIR("DISTINCT @, @", 2),
|
||||
CONCAT("CONCAT(@,@)", 2);
|
||||
|
||||
private String func;
|
||||
private int count;
|
||||
|
||||
@ -97,6 +97,7 @@ import org.apache.cloudstack.api.response.GuestOSResponse;
|
||||
import org.apache.cloudstack.api.response.GuestOsMappingResponse;
|
||||
import org.apache.cloudstack.api.response.GuestVlanRangeResponse;
|
||||
import org.apache.cloudstack.api.response.GuestVlanResponse;
|
||||
import org.apache.cloudstack.api.response.GuiThemeResponse;
|
||||
import org.apache.cloudstack.api.response.HostForMigrationResponse;
|
||||
import org.apache.cloudstack.api.response.HostResponse;
|
||||
import org.apache.cloudstack.api.response.HypervisorCapabilitiesResponse;
|
||||
@ -206,6 +207,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
|
||||
import org.apache.cloudstack.framework.jobs.AsyncJob;
|
||||
import org.apache.cloudstack.framework.jobs.AsyncJobManager;
|
||||
import org.apache.cloudstack.gui.theme.GuiThemeJoin;
|
||||
import org.apache.cloudstack.management.ManagementServerHost;
|
||||
import org.apache.cloudstack.network.BgpPeerVO;
|
||||
import org.apache.cloudstack.network.RoutedIpv4Manager;
|
||||
@ -5515,8 +5517,7 @@ public class ApiResponseHelper implements ResponseGenerator {
|
||||
SharedFSJoinVO sharedFSView = ApiDBUtils.newSharedFSView(sharedFS);
|
||||
return ApiDBUtils.newSharedFSResponse(view, sharedFSView);
|
||||
}
|
||||
|
||||
protected Map<String, ResourceIcon> getResourceIconsUsingOsCategory(List<TemplateResponse> responses) {
|
||||
protected Map<String, ResourceIcon> getResourceIconsUsingOsCategory(List<TemplateResponse> responses) {
|
||||
Set<Long> guestOsCategoryIds = responses.stream().map(TemplateResponse::getOsTypeCategoryId).collect(Collectors.toSet());
|
||||
Map<Long, ResourceIcon> guestOsCategoryIcons =
|
||||
resourceIconManager.getByResourceTypeAndIds(ResourceTag.ResourceObjectType.GuestOsCategory,
|
||||
@ -5550,4 +5551,28 @@ public class ApiResponseHelper implements ResponseGenerator {
|
||||
response.setResourceIconResponse(iconResponse);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public GuiThemeResponse createGuiThemeResponse(GuiThemeJoin guiThemeJoin) {
|
||||
GuiThemeResponse guiThemeResponse = new GuiThemeResponse();
|
||||
|
||||
Long callerId = CallContext.current().getCallingAccount().getAccountId();
|
||||
if (callerId != Account.ACCOUNT_ID_SYSTEM && _accountMgr.isRootAdmin(callerId)) {
|
||||
guiThemeResponse.setId(guiThemeJoin.getUuid());
|
||||
guiThemeResponse.setName(guiThemeJoin.getName());
|
||||
guiThemeResponse.setDescription(guiThemeJoin.getDescription());
|
||||
guiThemeResponse.setCommonNames(guiThemeJoin.getCommonNames());
|
||||
guiThemeResponse.setDomainIds(guiThemeJoin.getDomains());
|
||||
guiThemeResponse.setRecursiveDomains(guiThemeJoin.isRecursiveDomains());
|
||||
guiThemeResponse.setAccountIds(guiThemeJoin.getAccounts());
|
||||
guiThemeResponse.setPublic(guiThemeJoin.getIsPublic());
|
||||
guiThemeResponse.setCreated(guiThemeJoin.getCreated());
|
||||
guiThemeResponse.setRemoved(guiThemeJoin.getRemoved());
|
||||
}
|
||||
|
||||
guiThemeResponse.setJsonConfiguration(guiThemeJoin.getJsonConfiguration());
|
||||
guiThemeResponse.setCss(guiThemeJoin.getCss());
|
||||
guiThemeResponse.setResponseName("guithemes");
|
||||
|
||||
return guiThemeResponse;
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,6 +87,7 @@ import org.apache.cloudstack.api.command.admin.user.ListUsersCmd;
|
||||
import org.apache.cloudstack.api.command.user.account.ListAccountsCmd;
|
||||
import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd;
|
||||
import org.apache.cloudstack.api.command.user.event.ListEventsCmd;
|
||||
import org.apache.cloudstack.api.command.user.gui.theme.ListGuiThemesCmd;
|
||||
import org.apache.cloudstack.api.command.user.offering.ListDiskOfferingsCmd;
|
||||
import org.apache.cloudstack.api.command.user.offering.ListServiceOfferingsCmd;
|
||||
import org.apache.cloudstack.api.command.user.project.ListProjectInvitationsCmd;
|
||||
@ -967,6 +968,9 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
|
||||
final User user = ApiDBUtils.findUserById(userId);
|
||||
return commandAvailable(remoteAddress, commandName, user);
|
||||
} else {
|
||||
if (commandName.equalsIgnoreCase(ListGuiThemesCmd.class.getAnnotation(APICommand.class).name())) {
|
||||
return true;
|
||||
}
|
||||
// check against every available command to see if the command exists or not
|
||||
if (!s_apiNameCmdClassMap.containsKey(commandName) && !commandName.equals("login") && !commandName.equals("logout")) {
|
||||
final String errorMessage = "The given command " + commandName + " either does not exist, is not available" +
|
||||
|
||||
@ -37,6 +37,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.ApiServerService;
|
||||
@ -46,6 +47,7 @@ import org.apache.cloudstack.api.auth.APIAuthenticationManager;
|
||||
import org.apache.cloudstack.api.auth.APIAuthenticationType;
|
||||
import org.apache.cloudstack.api.auth.APIAuthenticator;
|
||||
import org.apache.cloudstack.api.command.user.consoleproxy.CreateConsoleEndpointCmd;
|
||||
import org.apache.cloudstack.api.command.user.gui.theme.ListGuiThemesCmd;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.managed.context.ManagedContext;
|
||||
import org.apache.cloudstack.utils.consoleproxy.ConsoleAccessUtils;
|
||||
@ -397,6 +399,8 @@ public class ApiServlet extends HttpServlet {
|
||||
CallContext.register(accountMgr.getSystemUser(), accountMgr.getSystemAccount());
|
||||
}
|
||||
setProjectContext(params);
|
||||
setGuiThemeParameterIfApiCallIsUnauthenticated(userId, command, req, params);
|
||||
|
||||
if (LOGGER.isTraceEnabled()) {
|
||||
LOGGER.trace(String.format("verifying request for user %s from %s with %d parameters",
|
||||
userId, remoteAddress.getHostAddress(), params.size()));
|
||||
@ -457,6 +461,19 @@ public class ApiServlet extends HttpServlet {
|
||||
}
|
||||
}
|
||||
|
||||
private void setGuiThemeParameterIfApiCallIsUnauthenticated(Long userId, String command, HttpServletRequest req, Map<String, Object[]> params) {
|
||||
String listGuiThemesApiName = ListGuiThemesCmd.class.getAnnotation(APICommand.class).name();
|
||||
|
||||
if (userId != null || !listGuiThemesApiName.equalsIgnoreCase(command)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String serverName = req.getServerName();
|
||||
LOGGER.info("Unauthenticated call to {} API, thus, the `commonName` parameter will be inferred as {}.", listGuiThemesApiName, serverName);
|
||||
params.put(ApiConstants.COMMON_NAME, new String[]{serverName});
|
||||
}
|
||||
|
||||
|
||||
private boolean checkIfAuthenticatorIsOf2FA(String command) {
|
||||
boolean verify2FA = false;
|
||||
APIAuthenticator apiAuthenticator = authManager.getAPIAuthenticator(command);
|
||||
|
||||
@ -403,6 +403,10 @@ import org.apache.cloudstack.api.command.user.firewall.UpdateFirewallRuleCmd;
|
||||
import org.apache.cloudstack.api.command.user.firewall.UpdatePortForwardingRuleCmd;
|
||||
import org.apache.cloudstack.api.command.user.guest.ListGuestOsCategoriesCmd;
|
||||
import org.apache.cloudstack.api.command.user.guest.ListGuestOsCmd;
|
||||
import org.apache.cloudstack.api.command.user.gui.theme.CreateGuiThemeCmd;
|
||||
import org.apache.cloudstack.api.command.user.gui.theme.ListGuiThemesCmd;
|
||||
import org.apache.cloudstack.api.command.user.gui.theme.RemoveGuiThemeCmd;
|
||||
import org.apache.cloudstack.api.command.user.gui.theme.UpdateGuiThemeCmd;
|
||||
import org.apache.cloudstack.api.command.user.iso.AttachIsoCmd;
|
||||
import org.apache.cloudstack.api.command.user.iso.CopyIsoCmd;
|
||||
import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd;
|
||||
@ -4187,6 +4191,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
cmdList.add(UpdateSecondaryStorageSelectorCmd.class);
|
||||
cmdList.add(RemoveSecondaryStorageSelectorCmd.class);
|
||||
cmdList.add(ListAffectedVmsForStorageScopeChangeCmd.class);
|
||||
cmdList.add(ListGuiThemesCmd.class);
|
||||
cmdList.add(UpdateGuiThemeCmd.class);
|
||||
cmdList.add(CreateGuiThemeCmd.class);
|
||||
cmdList.add(RemoveGuiThemeCmd.class);
|
||||
|
||||
// Out-of-band management APIs for admins
|
||||
cmdList.add(EnableOutOfBandManagementForHostCmd.class);
|
||||
|
||||
@ -0,0 +1,445 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.gui.theme;
|
||||
|
||||
import com.cloud.domain.Domain;
|
||||
import com.cloud.domain.dao.DomainDao;
|
||||
import com.cloud.event.ActionEvent;
|
||||
import com.cloud.event.EventTypes;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.db.EntityManager;
|
||||
import com.cloud.utils.db.Transaction;
|
||||
import com.cloud.utils.db.TransactionCallback;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import org.apache.cloudstack.api.ResponseGenerator;
|
||||
import org.apache.cloudstack.api.command.user.gui.theme.CreateGuiThemeCmd;
|
||||
import org.apache.cloudstack.api.command.user.gui.theme.ListGuiThemesCmd;
|
||||
import org.apache.cloudstack.api.command.user.gui.theme.RemoveGuiThemeCmd;
|
||||
import org.apache.cloudstack.api.command.user.gui.theme.UpdateGuiThemeCmd;
|
||||
import org.apache.cloudstack.api.response.GuiThemeResponse;
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.gui.theme.dao.GuiThemeDao;
|
||||
import org.apache.cloudstack.gui.theme.dao.GuiThemeDetailsDao;
|
||||
import org.apache.cloudstack.gui.theme.dao.GuiThemeJoinDao;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@Component
|
||||
public class GuiThemeServiceImpl implements GuiThemeService {
|
||||
|
||||
protected Logger logger = LogManager.getLogger(getClass());
|
||||
|
||||
private static final List<String> ALLOWED_PRIMITIVE_PROPERTIES = List.of("appTitle", "footer", "loginFooter", "logo", "minilogo", "banner");
|
||||
|
||||
private static final List<String> ALLOWED_ERROR_PROPERTIES = List.of("403", "404", "500");
|
||||
|
||||
private static final List<String> ALLOWED_PLUGIN_PROPERTIES = List.of("name", "path", "icon", "isExternalLink");
|
||||
|
||||
private static final String ERROR = "error";
|
||||
|
||||
private static final String PLUGINS = "plugins";
|
||||
|
||||
@Inject
|
||||
GuiThemeDao guiThemeDao;
|
||||
|
||||
@Inject
|
||||
GuiThemeDetailsDao guiThemeDetailsDao;
|
||||
|
||||
@Inject
|
||||
GuiThemeJoinDao guiThemeJoinDao;
|
||||
|
||||
@Inject
|
||||
ResponseGenerator responseGenerator;
|
||||
|
||||
@Inject
|
||||
EntityManager entityManager;
|
||||
|
||||
@Inject
|
||||
AccountDao accountDao;
|
||||
|
||||
@Inject
|
||||
DomainDao domainDao;
|
||||
|
||||
@Override
|
||||
public ListResponse<GuiThemeResponse> listGuiThemes(ListGuiThemesCmd cmd) {
|
||||
ListResponse<GuiThemeResponse> response = new ListResponse<>();
|
||||
Pair<List<GuiThemeJoinVO>, Integer> result;
|
||||
boolean listOnlyDefaultTheme = cmd.getListOnlyDefaultTheme();
|
||||
|
||||
if (listOnlyDefaultTheme) {
|
||||
result = retrieveDefaultTheme();
|
||||
} else if (CallContext.current().getCallingAccountId() == Account.ACCOUNT_ID_SYSTEM) {
|
||||
logger.info("Unauthenticated call to `listGuiThemes` API, ignoring all parameters, except `commonName`.");
|
||||
result = listGuiThemesWithNoAuthentication(cmd);
|
||||
} else {
|
||||
result = listGuiThemesInternal(cmd);
|
||||
}
|
||||
List<GuiThemeResponse> guiThemeResponses = new ArrayList<>();
|
||||
|
||||
for (GuiThemeJoin guiThemeJoin : result.first()) {
|
||||
GuiThemeResponse guiThemeResponse = responseGenerator.createGuiThemeResponse(guiThemeJoin);
|
||||
guiThemeResponses.add(guiThemeResponse);
|
||||
}
|
||||
|
||||
response.setResponses(guiThemeResponses);
|
||||
return response;
|
||||
}
|
||||
|
||||
private Pair<List<GuiThemeJoinVO>, Integer> retrieveDefaultTheme() {
|
||||
GuiThemeJoinVO defaultTheme = guiThemeJoinDao.findDefaultTheme();
|
||||
List<GuiThemeJoinVO> list = new ArrayList<>();
|
||||
|
||||
if (defaultTheme != null) {
|
||||
list.add(defaultTheme);
|
||||
}
|
||||
|
||||
return new Pair<>(list, list.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_GUI_THEME_CREATE, eventDescription = "Creating GUI theme")
|
||||
public GuiThemeJoin createGuiTheme(CreateGuiThemeCmd cmd) {
|
||||
String name = cmd.getName();
|
||||
String description = cmd.getDescription();
|
||||
String css = cmd.getCss();
|
||||
String jsonConfiguration = cmd.getJsonConfiguration();
|
||||
String commonNames = cmd.getCommonNames();
|
||||
String providedDomainIds = cmd.getDomainIds();
|
||||
String providedAccountIds = cmd.getAccountIds();
|
||||
boolean isPublic = cmd.getPublic();
|
||||
Boolean recursiveDomains = cmd.getRecursiveDomains();
|
||||
|
||||
CallContext.current().setEventDetails(String.format("Name: %s, AccountIDs: %s, DomainIDs: %s, RecursiveDomains: %s, CommonNames: %s", name, providedAccountIds,
|
||||
providedDomainIds, recursiveDomains, commonNames));
|
||||
|
||||
if (StringUtils.isAllBlank(css, jsonConfiguration)) {
|
||||
throw new CloudRuntimeException("Either the `css` or `jsonConfiguration` parameter must be informed.");
|
||||
}
|
||||
|
||||
validateParameters(jsonConfiguration, providedDomainIds, providedAccountIds, commonNames, null);
|
||||
|
||||
if (shouldSetGuiThemeToPrivate(providedDomainIds, providedAccountIds)) {
|
||||
isPublic = false;
|
||||
}
|
||||
|
||||
GuiThemeVO guiThemeVO = new GuiThemeVO(name, description, css, jsonConfiguration, recursiveDomains, isPublic, new Date(), null);
|
||||
guiThemeDao.persist(guiThemeVO);
|
||||
persistGuiThemeDetails(guiThemeVO.getId(), commonNames, providedDomainIds, providedAccountIds);
|
||||
return guiThemeJoinDao.findById(guiThemeVO.getId());
|
||||
}
|
||||
|
||||
protected void persistGuiThemeDetails(long guiThemeId, String commonNames, String providedDomainIds, String providedAccountIds) {
|
||||
persistDetailValueIfNotNull(guiThemeId, commonNames, "commonName");
|
||||
persistDetailValueIfNotNull(guiThemeId, providedDomainIds, "domain");
|
||||
persistDetailValueIfNotNull(guiThemeId, providedAccountIds, "account");
|
||||
}
|
||||
|
||||
protected void persistDetailValueIfNotNull(long guiThemeId, String providedParameter, String type) {
|
||||
if (providedParameter == null) {
|
||||
logger.trace("GUI theme provided parameter `{}` is null; therefore, it will be ignored.", type);
|
||||
return;
|
||||
}
|
||||
for (String splitParameter : StringUtils.deleteWhitespace(providedParameter).split(",")) {
|
||||
guiThemeDetailsDao.persist(new GuiThemeDetailsVO(guiThemeId, type, splitParameter));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected boolean shouldSetGuiThemeToPrivate(String providedDomainIds, String providedAccountIds) {
|
||||
if (StringUtils.isNotBlank(providedAccountIds)) {
|
||||
logger.info("Parameter `accountIds` was informed during GUI theme creation, therefore, `isPublic` will be set to `false`.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(providedDomainIds)) {
|
||||
logger.info("Parameter `domainIds` was informed during GUI theme creation, therefore, `isPublic` will be set to `false`.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A GUI theme is only considered the default one if the parameters `commonNames`, `domainIds` and `accountIds` are all blank.
|
||||
* @return true if all parameters are blank, false otherwise.
|
||||
*/
|
||||
protected boolean isConsideredDefaultTheme(String commonNames, String providedDomainIds, String providedAccountIds) {
|
||||
return StringUtils.isAllBlank(commonNames, providedDomainIds, providedAccountIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* There can only be one default theme registered, therefore, a {@link CloudRuntimeException} will be thrown if:
|
||||
* <ul>
|
||||
* <li>There is already a default theme registered when creating a new GUI theme.</li>
|
||||
* <li>Or, the GUI theme to be updated is not the default theme already registered.</li>
|
||||
* </ul>
|
||||
*/
|
||||
protected void checkIfDefaultThemeIsAllowed(String commonNames, String providedDomainIds, String providedAccountIds, Long idOfThemeToBeUpdated) {
|
||||
if (!isConsideredDefaultTheme(commonNames, providedDomainIds, providedAccountIds)) {
|
||||
logger.info("The GUI theme will not be considered as the default one, as the `commonNames`, `domainIds` and `accountIds` are not all blank.");
|
||||
return;
|
||||
}
|
||||
|
||||
GuiThemeJoinVO defaultTheme = guiThemeJoinDao.findDefaultTheme();
|
||||
|
||||
if (defaultTheme != null && (idOfThemeToBeUpdated == null || defaultTheme.getId() != idOfThemeToBeUpdated)) {
|
||||
throw new CloudRuntimeException(String.format("Only one default GUI theme is allowed. Remove the current default theme %s and try again.", defaultTheme));
|
||||
}
|
||||
|
||||
logger.info("The parameters `commonNames`, `domainIds` and `accountIds` were not informed. The created theme will be considered as the default theme.");
|
||||
}
|
||||
|
||||
protected Pair<List<GuiThemeJoinVO>, Integer> listGuiThemesWithNoAuthentication(ListGuiThemesCmd cmd) {
|
||||
return guiThemeJoinDao.listGuiThemesWithNoAuthentication(cmd.getCommonName());
|
||||
}
|
||||
|
||||
|
||||
protected Pair<List<GuiThemeJoinVO>, Integer> listGuiThemesInternal(ListGuiThemesCmd cmd) {
|
||||
Long id = cmd.getId();
|
||||
String name = cmd.getName();
|
||||
String commonName = cmd.getCommonName();
|
||||
String domainUuid = cmd.getDomainId() == null ? null : domainDao.findById(cmd.getDomainId()).getUuid();
|
||||
String accountUuid = cmd.getAccountId() == null ? null : accountDao.findById(cmd.getAccountId()).getUuid();
|
||||
boolean listAll = cmd.getListAll();
|
||||
boolean showRemoved = cmd.getShowRemoved();
|
||||
Boolean showPublic = cmd.getShowPublic();
|
||||
|
||||
return guiThemeJoinDao.listGuiThemes(id, name, commonName, domainUuid, accountUuid, listAll, showRemoved, showPublic);
|
||||
}
|
||||
|
||||
protected void validateParameters(String jsonConfig, String domainIds, String accountIds, String commonNames, Long idOfThemeToBeUpdated) {
|
||||
if (isConsideredDefaultTheme(commonNames, domainIds, accountIds)) {
|
||||
checkIfDefaultThemeIsAllowed(commonNames, domainIds, accountIds, idOfThemeToBeUpdated);
|
||||
}
|
||||
|
||||
validateObjectUuids(accountIds, Account.class);
|
||||
validateObjectUuids(domainIds, Domain.class);
|
||||
validateJsonConfiguration(jsonConfig);
|
||||
}
|
||||
|
||||
protected void validateJsonConfiguration(String jsonConfig) {
|
||||
if (jsonConfig == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
|
||||
try {
|
||||
JsonElement jsonElement = new JsonParser().parse(jsonConfig);
|
||||
Set<Map.Entry<String, JsonElement>> entries = jsonElement.getAsJsonObject().entrySet();
|
||||
entries.stream().forEach(entry -> validateJsonAttributes(entry, jsonObject));
|
||||
} catch (JsonSyntaxException exception) {
|
||||
logger.error("The following exception was thrown while parsing the JSON object: [{}].", exception.getMessage());
|
||||
throw new CloudRuntimeException("Specified JSON configuration is not a valid JSON object.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the informed JSON attributes considering the allowed properties by the API, any invalid option is ignored.
|
||||
* All valid options are added to a {@link JsonObject} that will be considered as the final JSON configuration used by the GUI theme.
|
||||
*/
|
||||
private void validateJsonAttributes(Map.Entry<String, JsonElement> entry, JsonObject jsonObject) {
|
||||
JsonElement entryValue = entry.getValue();
|
||||
String entryKey = entry.getKey();
|
||||
|
||||
if (entryValue.isJsonPrimitive() && ALLOWED_PRIMITIVE_PROPERTIES.contains(entryKey)) {
|
||||
logger.trace("The JSON attribute [{}] is a valid option.", entryKey);
|
||||
jsonObject.add(entryKey, entryValue);
|
||||
} else if (entryValue.isJsonObject() && ERROR.equals(entryKey)) {
|
||||
validateErrorAttribute(entry, jsonObject);
|
||||
} else if (entryValue.isJsonArray() && PLUGINS.equals(entryKey)) {
|
||||
validatePluginsAttribute(entry, jsonObject);
|
||||
} else {
|
||||
warnOfInvalidJsonAttribute(entryKey);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link JsonObject} with only the valid options for the Plugins' properties specified in the {@link #ALLOWED_PLUGIN_PROPERTIES}.
|
||||
*/
|
||||
protected void validatePluginsAttribute(Map.Entry<String, JsonElement> entry, JsonObject jsonObject) {
|
||||
Set<Map.Entry<String, JsonElement>> entries = entry.getValue().getAsJsonArray().get(0).getAsJsonObject().entrySet();
|
||||
JsonObject objectToBeAdded = createJsonObject(entries, ALLOWED_PLUGIN_PROPERTIES);
|
||||
JsonArray jsonArray = new JsonArray();
|
||||
|
||||
if (objectToBeAdded.entrySet().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
jsonArray.add(objectToBeAdded);
|
||||
jsonObject.add(entry.getKey(), jsonArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link JsonObject} with only the valid options for the Error's properties specified in the {@link #ALLOWED_ERROR_PROPERTIES}.
|
||||
*/
|
||||
protected void validateErrorAttribute(Map.Entry<String, JsonElement> entry, JsonObject jsonObject) {
|
||||
Set<Map.Entry<String, JsonElement>> entries = entry.getValue().getAsJsonObject().entrySet();
|
||||
JsonObject objectToBeAdded = createJsonObject(entries, ALLOWED_ERROR_PROPERTIES);
|
||||
|
||||
if (objectToBeAdded.entrySet().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
jsonObject.add(entry.getKey(), objectToBeAdded);
|
||||
}
|
||||
|
||||
protected JsonObject createJsonObject(Set<Map.Entry<String, JsonElement>> entries, List<String> allowedProperties) {
|
||||
JsonObject objectToBeAdded = new JsonObject();
|
||||
|
||||
for (Map.Entry<String, JsonElement> recursiveEntry : entries) {
|
||||
String entryKey = recursiveEntry.getKey();
|
||||
|
||||
if (!allowedProperties.contains(entryKey)) {
|
||||
warnOfInvalidJsonAttribute(entryKey);
|
||||
continue;
|
||||
}
|
||||
objectToBeAdded.add(entryKey, recursiveEntry.getValue());
|
||||
}
|
||||
|
||||
return objectToBeAdded;
|
||||
}
|
||||
|
||||
protected void warnOfInvalidJsonAttribute(String entryKey) {
|
||||
logger.warn("The JSON attribute [{}] is not a valid option, therefore, it will be ignored.", entryKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate if the comma separated list of UUIDs of the fields {@link GuiThemeJoinVO#getAccounts()} and {@link GuiThemeJoinVO#getDomains()} are valid.
|
||||
* @param providedIds a comma separated list of UUIDs of {@link Account} or {@link Domain}
|
||||
* @param clazz the class to infer the DAO object. Valid options are: {@link Account} and {@link Domain}
|
||||
*/
|
||||
protected void validateObjectUuids(String providedIds, Class clazz) {
|
||||
if (StringUtils.isBlank(providedIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String[] commaSeparatedIds = providedIds.split("\\s*,\\s*");
|
||||
for (String id : commaSeparatedIds) {
|
||||
Object objectVO = entityManager.findByUuid(clazz, id);
|
||||
|
||||
if (objectVO == null) {
|
||||
throw new CloudRuntimeException(String.format("The %s ID %s does not exist. Verify the informed IDs and try again.", clazz.getSimpleName(), id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_GUI_THEME_UPDATE, eventDescription = "Updating GUI theme")
|
||||
public GuiThemeJoin updateGuiTheme(UpdateGuiThemeCmd cmd) {
|
||||
Long guiThemeId = cmd.getId();
|
||||
GuiThemeJoinVO guiThemeJoinVO = guiThemeJoinDao.findById(guiThemeId);
|
||||
|
||||
String name = cmd.getName();
|
||||
String description = cmd.getDescription();
|
||||
String css = cmd.getCss();
|
||||
String jsonConfiguration = cmd.getJsonConfiguration();
|
||||
String commonNames = cmd.getCommonNames() == null ? guiThemeJoinVO.getCommonNames() : cmd.getCommonNames();
|
||||
String providedDomainIds = cmd.getDomainIds() == null ? guiThemeJoinVO.getDomains() : cmd.getDomainIds();
|
||||
String providedAccountIds = cmd.getAccountIds() == null ? guiThemeJoinVO.getAccounts() : cmd.getAccountIds();
|
||||
Boolean isPublic = cmd.getIsPublic();
|
||||
Boolean recursiveDomains = cmd.getRecursiveDomains();
|
||||
|
||||
CallContext.current().setEventDetails(String.format("ID: %s, Name: %s, AccountIDs: %s, DomainIDs: %s, RecursiveDomains: %s, CommonNames: %s", guiThemeId, name,
|
||||
providedAccountIds, providedDomainIds, recursiveDomains, commonNames));
|
||||
|
||||
validateParameters(jsonConfiguration, providedDomainIds, providedAccountIds, commonNames, guiThemeId);
|
||||
|
||||
if (shouldSetGuiThemeToPrivate(providedDomainIds, providedAccountIds)) {
|
||||
isPublic = false;
|
||||
}
|
||||
|
||||
return persistGuiTheme(guiThemeId, name, description, css, jsonConfiguration, commonNames, providedDomainIds, providedAccountIds, isPublic, recursiveDomains);
|
||||
}
|
||||
|
||||
protected GuiThemeJoinVO persistGuiTheme(Long guiThemeId, String name, String description, String css, String jsonConfiguration, String commonNames, String providedDomainIds,
|
||||
String providedAccountIds, Boolean isPublic, Boolean recursiveDomains){
|
||||
return Transaction.execute((TransactionCallback<GuiThemeJoinVO>) status -> {
|
||||
GuiThemeVO guiThemeVO = guiThemeDao.findById(guiThemeId);
|
||||
|
||||
if (name != null) {
|
||||
guiThemeVO.setName(ifBlankReturnNull(name));
|
||||
}
|
||||
|
||||
if (description != null) {
|
||||
guiThemeVO.setDescription(ifBlankReturnNull(description));
|
||||
}
|
||||
|
||||
if (css != null) {
|
||||
guiThemeVO.setCss(css);
|
||||
}
|
||||
|
||||
if (jsonConfiguration != null) {
|
||||
guiThemeVO.setJsonConfiguration(jsonConfiguration);
|
||||
}
|
||||
|
||||
if (isPublic != null) {
|
||||
guiThemeVO.setIsPublic(isPublic);
|
||||
}
|
||||
|
||||
if (recursiveDomains != null) {
|
||||
guiThemeVO.setRecursiveDomains(recursiveDomains);
|
||||
}
|
||||
|
||||
logger.trace("Persisting GUI theme [{}] with CSS [{}] and JSON configuration [{}].", guiThemeVO, guiThemeVO.getCss(), guiThemeVO.getJsonConfiguration());
|
||||
|
||||
guiThemeDao.persist(guiThemeVO);
|
||||
guiThemeDetailsDao.expungeByGuiThemeId(guiThemeId);
|
||||
persistGuiThemeDetails(guiThemeId, commonNames, providedDomainIds, providedAccountIds);
|
||||
|
||||
return guiThemeJoinDao.findById(guiThemeId);
|
||||
});
|
||||
}
|
||||
|
||||
protected String ifBlankReturnNull(String value) {
|
||||
if (StringUtils.isBlank(value)) {
|
||||
return null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_GUI_THEME_REMOVE, eventDescription = "Removing GUI theme")
|
||||
public void removeGuiTheme(RemoveGuiThemeCmd cmd) {
|
||||
Long guiThemeId = cmd.getId();
|
||||
GuiThemeVO guiThemeVO = guiThemeDao.findById(guiThemeId);
|
||||
CallContext.current().setEventDetails(String.format("ID: %s", guiThemeId));
|
||||
|
||||
if (guiThemeVO != null) {
|
||||
guiThemeDao.remove(guiThemeId);
|
||||
} else {
|
||||
logger.error("Unable to find a GUI theme with the specified ID [{}].", guiThemeId);
|
||||
throw new CloudRuntimeException("Unable to find a GUI theme with the specified ID.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -390,4 +390,5 @@
|
||||
<property name="asyncJobDispatcher" ref="ApiAsyncJobDispatcher" />
|
||||
</bean>
|
||||
|
||||
<bean id="guiThemeServiceImpl" class="org.apache.cloudstack.gui.theme.GuiThemeServiceImpl" />
|
||||
</beans>
|
||||
|
||||
@ -0,0 +1,215 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package org.apache.cloudstack.gui.theme;
|
||||
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.db.EntityManager;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import org.apache.cloudstack.api.command.user.gui.theme.ListGuiThemesCmd;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.gui.theme.dao.GuiThemeJoinDaoImpl;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GuiThemeServiceImplTest {
|
||||
|
||||
@Mock
|
||||
GuiThemeJoinDaoImpl guiThemeJoinDaoMock;
|
||||
|
||||
@Mock
|
||||
GuiThemeJoinVO guiThemeJoinVOMock;
|
||||
|
||||
@Mock
|
||||
EntityManager entityManagerMock;
|
||||
|
||||
@Mock
|
||||
Object objectMock;
|
||||
|
||||
@Mock
|
||||
ListGuiThemesCmd listGuiThemesCmdMock;
|
||||
|
||||
@Spy
|
||||
@InjectMocks
|
||||
GuiThemeServiceImpl guiThemeServiceSpy = new GuiThemeServiceImpl();
|
||||
|
||||
private static final String COMMON_NAME = "*acme.com,acm2.com";
|
||||
|
||||
private static final String DOMAIN_IDS = "1,2,3";
|
||||
|
||||
private static final String ACCOUNT_IDS = "4,5,6";
|
||||
|
||||
private static final String BLANK_STRING = "";
|
||||
|
||||
@Test
|
||||
public void listGuiThemesTestShouldIgnoreParametersWhenItIsCalledUnauthenticated() {
|
||||
Pair<List<GuiThemeJoinVO>, Integer> emptyPair = new Pair<>(new ArrayList<>(), 0);
|
||||
|
||||
Long accountId = Account.ACCOUNT_ID_SYSTEM;
|
||||
|
||||
try (MockedStatic<CallContext> callContextMocked = Mockito.mockStatic(CallContext.class)) {
|
||||
CallContext callContextMock = Mockito.mock(CallContext.class);
|
||||
callContextMocked.when(CallContext::current).thenReturn(callContextMock);
|
||||
Mockito.doReturn(accountId).when(callContextMock).getCallingAccountId();
|
||||
Mockito.doReturn(emptyPair).when(guiThemeServiceSpy).listGuiThemesWithNoAuthentication(Mockito.nullable(ListGuiThemesCmd.class));
|
||||
Mockito.when(listGuiThemesCmdMock.getListOnlyDefaultTheme()).thenReturn(false);
|
||||
guiThemeServiceSpy.listGuiThemes(listGuiThemesCmdMock);
|
||||
Mockito.verify(guiThemeServiceSpy, Mockito.times(1)).listGuiThemesWithNoAuthentication(Mockito.nullable(ListGuiThemesCmd.class));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listGuiThemesTestShouldCallNormalFlowWhenAuthenticated() {
|
||||
Pair<List<GuiThemeVO>, Integer> emptyPair = new Pair<>(new ArrayList<>(), 0);
|
||||
|
||||
Long accountId = 3L;
|
||||
|
||||
try (MockedStatic<CallContext> callContextMocked = Mockito.mockStatic(CallContext.class)) {
|
||||
CallContext callContextMock = Mockito.mock(CallContext.class);
|
||||
callContextMocked.when(CallContext::current).thenReturn(callContextMock);
|
||||
Mockito.doReturn(accountId).when(callContextMock).getCallingAccountId();
|
||||
Mockito.doReturn(emptyPair).when(guiThemeServiceSpy).listGuiThemesInternal(Mockito.nullable(ListGuiThemesCmd.class));
|
||||
Mockito.when(listGuiThemesCmdMock.getListOnlyDefaultTheme()).thenReturn(false);
|
||||
guiThemeServiceSpy.listGuiThemes(listGuiThemesCmdMock);
|
||||
Mockito.verify(guiThemeServiceSpy, Mockito.times(1)).listGuiThemesInternal(Mockito.nullable(ListGuiThemesCmd.class));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listGuiThemesTestListOnlyDefaultThemesShouldCallFindDefaultTheme() {
|
||||
Mockito.when(listGuiThemesCmdMock.getListOnlyDefaultTheme()).thenReturn(true);
|
||||
guiThemeServiceSpy.listGuiThemes(listGuiThemesCmdMock);
|
||||
Mockito.verify(guiThemeJoinDaoMock, Mockito.times(1)).findDefaultTheme();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSetGuiThemeToPrivateTestDomainIdsAndAccountIdsAreBlankShouldReturnFalse() {
|
||||
boolean result = guiThemeServiceSpy.shouldSetGuiThemeToPrivate(BLANK_STRING, BLANK_STRING);
|
||||
|
||||
Assert.assertFalse(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSetGuiThemeToPrivateTestDomainIdsNotBlankAndAccountIdsIsBlankShouldReturnTrue() {
|
||||
boolean result = guiThemeServiceSpy.shouldSetGuiThemeToPrivate(DOMAIN_IDS, BLANK_STRING);
|
||||
|
||||
Assert.assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSetGuiThemeToPrivateTestDomainIdsIsBlankAndAccountIdsIsNotBlankShouldReturnTrue() {
|
||||
boolean result = guiThemeServiceSpy.shouldSetGuiThemeToPrivate(BLANK_STRING, ACCOUNT_IDS);
|
||||
|
||||
Assert.assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSetGuiThemeToPrivateTestDomainIdsAndAccountIdsAreNotBlankShouldReturnTrue() {
|
||||
boolean result = guiThemeServiceSpy.shouldSetGuiThemeToPrivate(DOMAIN_IDS, ACCOUNT_IDS);
|
||||
|
||||
Assert.assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateObjectUuidsTestProvidedUuidsIsNullShouldNotThrowCloudRuntimeException() {
|
||||
guiThemeServiceSpy.validateObjectUuids(null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateObjectUuidsTestProvidedUuidsIsBlankShouldNotThrowCloudRuntimeException() {
|
||||
guiThemeServiceSpy.validateObjectUuids(BLANK_STRING, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateObjectUuidsTestProvidedUuidsIsBlankAndCommaSeparatedShouldNotThrowCloudRuntimeException() {
|
||||
String blankCommaSeparatedString = ",,,";
|
||||
guiThemeServiceSpy.validateObjectUuids(blankCommaSeparatedString, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateObjectUuidsTestProvidedUuidIsValidShouldNotThrowCloudRuntimeException() {
|
||||
String validUuid = "4";
|
||||
|
||||
Mockito.when(entityManagerMock.findByUuid(Mockito.any(Class.class), Mockito.anyString())).thenReturn(objectMock);
|
||||
guiThemeServiceSpy.validateObjectUuids(validUuid, Account.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateObjectUuidsTestProvidedUuidsAreValidShouldNotThrowCloudRuntimeException() {
|
||||
Mockito.when(entityManagerMock.findByUuid(Mockito.any(Class.class), Mockito.anyString())).thenReturn(objectMock);
|
||||
guiThemeServiceSpy.validateObjectUuids(ACCOUNT_IDS, Account.class);
|
||||
}
|
||||
|
||||
@Test(expected = CloudRuntimeException.class)
|
||||
public void validateObjectUuidsTestProvidedUuidsAreNotValidShouldThrowCloudRuntimeException() {
|
||||
Mockito.when(entityManagerMock.findByUuid(Mockito.any(Class.class), Mockito.anyString())).thenReturn(null);
|
||||
guiThemeServiceSpy.validateObjectUuids(ACCOUNT_IDS, Account.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkIfDefaultThemeIsAllowedTestThemeIsNotConsideredDefault() {
|
||||
Mockito.when(guiThemeServiceSpy.isConsideredDefaultTheme(Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn(false);
|
||||
|
||||
guiThemeServiceSpy.checkIfDefaultThemeIsAllowed(COMMON_NAME, BLANK_STRING, BLANK_STRING, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkIfDefaultThemeIsAllowedTestThemeIsConsideredDefaultAndThereIsNotADefaultThemeRegistered() {
|
||||
Mockito.when(guiThemeServiceSpy.isConsideredDefaultTheme(Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn(true);
|
||||
Mockito.when(guiThemeJoinDaoMock.findDefaultTheme()).thenReturn(null);
|
||||
|
||||
guiThemeServiceSpy.checkIfDefaultThemeIsAllowed(BLANK_STRING, BLANK_STRING, BLANK_STRING, null);
|
||||
}
|
||||
|
||||
@Test(expected = CloudRuntimeException.class)
|
||||
public void checkIfDefaultThemeIsAllowedTestThemeIsConsideredDefaultAndThereIsADefaultThemeRegisteredShouldThrowCloudRuntimeException() {
|
||||
Mockito.when(guiThemeServiceSpy.isConsideredDefaultTheme(Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn(true);
|
||||
Mockito.when(guiThemeJoinDaoMock.findDefaultTheme()).thenReturn(guiThemeJoinVOMock);
|
||||
|
||||
guiThemeServiceSpy.checkIfDefaultThemeIsAllowed(BLANK_STRING, BLANK_STRING, BLANK_STRING, null);
|
||||
}
|
||||
|
||||
@Test(expected = CloudRuntimeException.class)
|
||||
public void checkIfDefaultThemeIsAllowedTestThemeIsConsideredDefaultAndWillBeUpdatedAndIsDifferentIdShouldThrowCloudRuntimeException() {
|
||||
Mockito.when(guiThemeServiceSpy.isConsideredDefaultTheme(Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn(true);
|
||||
Mockito.when(guiThemeJoinDaoMock.findDefaultTheme()).thenReturn(guiThemeJoinVOMock);
|
||||
Mockito.when(guiThemeJoinVOMock.getId()).thenReturn(1L);
|
||||
|
||||
guiThemeServiceSpy.checkIfDefaultThemeIsAllowed(BLANK_STRING, BLANK_STRING, BLANK_STRING, 2L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkIfDefaultThemeIsAllowedTestThemeIsConsideredDefaultAndWillBeUpdatedAndIsTheSameShouldAllowUpdate() {
|
||||
Mockito.when(guiThemeServiceSpy.isConsideredDefaultTheme(Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn(true);
|
||||
Mockito.when(guiThemeJoinDaoMock.findDefaultTheme()).thenReturn(guiThemeJoinVOMock);
|
||||
Mockito.when(guiThemeJoinVOMock.getId()).thenReturn(1L);
|
||||
|
||||
guiThemeServiceSpy.checkIfDefaultThemeIsAllowed(BLANK_STRING, BLANK_STRING, BLANK_STRING, 1L);
|
||||
}
|
||||
}
|
||||
@ -260,7 +260,11 @@ known_categories = {
|
||||
'addNodesToKubernetesCluster': 'Kubernetes Service',
|
||||
'removeNodesFromKubernetesCluster': 'Kubernetes Service',
|
||||
'configureStorageAccess': 'Storage Access Groups',
|
||||
'listStorageAccessGroups': 'Storage Access Groups'
|
||||
'listStorageAccessGroups': 'Storage Access Groups',
|
||||
'listGuiThemes': 'GUI Theme',
|
||||
'createGuiTheme': 'GUI Theme',
|
||||
'updateGuiTheme': 'GUI Theme',
|
||||
'removeGuiTheme': 'GUI Theme'
|
||||
}
|
||||
|
||||
|
||||
|
||||
116
ui/public/assets/asf-logo.svg
Normal file
116
ui/public/assets/asf-logo.svg
Normal file
@ -0,0 +1,116 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 7127.6 2890" enable-background="new 0 0 7127.6 2890" xml:space="preserve">
|
||||
<path fill="#6D6E71" d="M7104.7,847.8c15.3,15.3,22.9,33.7,22.9,55.2c0,21.5-7.6,39.9-22.9,55.4c-15.3,15.4-33.8,23.1-55.6,23.1 c-21.8,0-40.2-7.6-55.4-22.9c-15.1-15.3-22.7-33.7-22.7-55.2c0-21.5,7.6-39.9,22.9-55.4c15.3-15.4,33.7-23.1,55.4-23.1 C7070.9,824.9,7089.4,832.5,7104.7,847.8z M7098.1,951.9c13.3-13.6,20-29.8,20-48.7s-6.6-35-19.8-48.5 c-13.2-13.4-29.4-20.1-48.6-20.1c-19.2,0-35.4,6.7-48.7,20.2c-13.3,13.5-19.9,29.7-19.9,48.7c0,19,6.6,35.2,19.7,48.6 c13.1,13.4,29.3,20.1,48.5,20.1S7084.7,965.4,7098.1,951.9z M7087.1,888.1c0,14-6.1,22.8-18.4,26.4l22.5,30.5h-18.2l-20.3-28.3 h-18.6v28.3h-14.7v-84.6h31.8c12.8,0,22,2.2,27.6,6.6C7084.4,871.4,7087.1,878.4,7087.1,888.1z M7068.2,900c3-2.4,4.4-6.5,4.4-12 c0-5.5-1.5-9.4-4.5-11.6c-3-2.2-8.4-3.2-16-3.2h-18v30.5h17.5C7059.7,903.6,7065.3,902.4,7068.2,900z"/>
|
||||
<path fill="#6D6E71" d="M1803.6,499.8v155.4h-20V499.8h-56.8v-19.2h133.9v19.2H1803.6z"/>
|
||||
<path fill="#6D6E71" d="M2082.2,655.2v-76.9h-105.2v76.9h-20V480.5h20v78.9h105.2v-78.9h20v174.7H2082.2z"/>
|
||||
<path fill="#6D6E71" d="M2241.4,499.8v57.4h88.1v19.2h-88.1v59.8h101.8v19h-121.8V480.5H2340v19.2H2241.4z"/>
|
||||
<path fill="#D22128" d="M1574.5,1852.4l417.3-997.6h80.1l417.3,997.6h-105.4l-129.3-311.9h-448.2l-127.9,311.9H1574.5z M2032.6,970 l-205.1,493.2h404.7L2032.6,970z"/>
|
||||
<path fill="#D22128" d="M2596.9,1852.4V854.8H3010c171.4,0,295.1,158.8,295.1,313.3c0,163-115.2,316.1-286.6,316.1h-324.6v368.1 H2596.9z M2693.9,1397.1h318.9c118,0,193.9-108.2,193.9-229c0-125.1-92.7-226.2-202.3-226.2h-310.5V1397.1z"/>
|
||||
<path fill="#D22128" d="M3250.5,1852.4l417.3-997.6h80.1l417.3,997.6h-105.4l-129.3-311.9h-448.2l-127.9,311.9H3250.5z M3708.6,970 l-205.1,493.2h404.7L3708.6,970z"/>
|
||||
<path fill="#D22128" d="M4637.3,849.1c177,0,306.3,89.9,368.1,217.8l-78.7,47.8c-63.2-132.1-186.9-177-295.1-177 c-238.9,0-369.5,213.6-369.5,414.5c0,220.6,161.6,420.1,373.7,420.1c112.4,0,244.5-56.2,307.7-185.5l81.5,42.1 c-64.6,148.9-241.7,231.8-394.8,231.8c-274,0-466.5-261.3-466.5-514.2C4163.8,1106.3,4336.6,849.1,4637.3,849.1z"/>
|
||||
<path fill="#D22128" d="M5949.1,854.8v997.6h-98.4v-466.5h-591.5v466.5h-96.9V854.8h96.9v444h591.5v-444H5949.1z"/>
|
||||
<path fill="#D22128" d="M6844.6,1765.2v87.1h-670.2V854.8H6832v87.1h-560.6v359.7h489v82.9h-489v380.8H6844.6z"/>
|
||||
<path fill="#6D6E71" d="M1667.6,2063.6c11.8,3.5,22.2,8.3,31,14.2l-10.3,22.6c-9-6-18.6-10.4-28.9-13.4c-10.2-2.9-20-4.4-29.2-4.4 c-13.6,0-24.5,2.4-32.6,7.3c-8.1,4.9-12.2,11.8-12.2,20.7c0,7.6,2.3,14,6.8,19c4.5,5,10.2,8.9,17,11.7c6.8,2.8,16.1,6,28,9.6 c14.4,4.6,26,8.9,34.7,12.9c8.8,4,16.3,9.9,22.5,17.8c6.2,7.8,9.3,18.2,9.3,31c0,11.7-3.2,21.8-9.5,30.6 c-6.3,8.7-15.3,15.5-26.8,20.3c-11.6,4.8-24.9,7.2-40,7.2c-15.1,0-29.7-2.9-43.9-8.7c-14.2-5.8-26.4-13.6-36.6-23.4l10.7-21.6 c9.6,9.4,20.7,16.7,33.3,21.9c12.6,5.2,24.8,7.8,36.8,7.8c15.3,0,27.3-3,36.1-8.9c8.8-5.9,13.2-13.9,13.2-23.9 c0-7.8-2.3-14.3-6.9-19.4c-4.6-5.1-10.3-9-17.1-11.9c-6.8-2.8-16.1-6-28-9.6c-14.2-4.2-25.7-8.3-34.6-12.2 c-8.9-3.9-16.4-9.7-22.5-17.5c-6.1-7.7-9.2-17.9-9.2-30.6c0-10.9,3-20.4,9-28.6c6-8.2,14.6-14.6,25.6-19.1 c11.1-4.5,23.8-6.8,38.2-6.8C1643.8,2058.3,1655.7,2060.1,1667.6,2063.6z"/>
|
||||
<path fill="#6D6E71" d="M1980.1,2072.8c16.8,9.4,30.2,22.3,40,38.4c9.8,16.2,14.8,33.9,14.8,53.3c0,19.5-4.9,37.4-14.8,53.6 c-9.8,16.3-23.2,29.1-40,38.6c-16.8,9.5-35.3,14.3-55.2,14.3c-20.3,0-38.8-4.7-55.7-14.3c-16.8-9.5-30.2-22.4-40-38.6 c-9.8-16.3-14.8-34.1-14.8-53.6c0-19.5,4.9-37.3,14.8-53.5c9.8-16.2,23.2-29,40-38.3c16.8-9.4,35.4-14,55.7-14 C1944.8,2058.6,1963.2,2063.3,1980.1,2072.8z M1881.9,2092.7c-13.1,7.4-23.6,17.5-31.4,30.1c-7.8,12.6-11.8,26.5-11.8,41.7 c0,15.3,3.9,29.3,11.8,42c7.8,12.7,18.3,22.8,31.4,30.2c13.1,7.4,27.4,11.1,42.9,11.1c15.5,0,29.7-3.7,42.7-11.1 c13-7.4,23.3-17.4,31.1-30.2c7.7-12.7,11.6-26.7,11.6-42s-3.9-29.2-11.6-41.8c-7.7-12.6-18.1-22.6-31.1-30 c-13-7.4-27.2-11.2-42.6-11.2C1909.4,2081.5,1895.1,2085.2,1881.9,2092.7z"/>
|
||||
<path fill="#6D6E71" d="M2186.5,2082.4v74h98.4v23.2h-98.4v90.2h-24.1v-210.6h133.8v23.2H2186.5z"/>
|
||||
<path fill="#6D6E71" d="M2491.6,2082.4v187.4h-24.1v-187.4h-68.4v-23.2h161.4v23.2H2491.6z"/>
|
||||
<path fill="#6D6E71" d="M2871.8,2269.8l-56.8-177.4l-57.6,177.4h-24.5l-70.5-210.6h25.9l57.9,182.7l57.1-182.4l24.1-0.3l57.7,182.7 l57.1-182.7h25l-70.6,210.6H2871.8z"/>
|
||||
<path fill="#6D6E71" d="M3087.3,2216.6l-23.5,53.2h-25.6l94.4-210.6h25l94.1,210.6h-26.1l-23.5-53.2H3087.3z M3144.5,2086.6 l-46.9,106.8h94.4L3144.5,2086.6z"/>
|
||||
<path fill="#6D6E71" d="M3461.1,2202.7c-6,0.4-10.7,0.6-14.1,0.6h-56v66.5H3367v-210.6h80c26.2,0,46.6,6.2,61.2,18.5 c14.5,12.3,21.8,29.8,21.8,52.3c0,17.2-4.1,31.7-12.2,43.3c-8.1,11.6-19.8,20-35,25l49.2,71.5h-27.3L3461.1,2202.7z M3491.3,2167.6 c10.3-8.4,15.5-20.8,15.5-37c0-15.9-5.2-27.9-15.5-36c-10.3-8.1-25.1-12.2-44.3-12.2h-56v97.8h56 C3466.2,2180.2,3481,2176,3491.3,2167.6z"/>
|
||||
<path fill="#6D6E71" d="M3688.3,2082.4v69.2h106.2v23.2h-106.2v72.1h122.8v22.9h-146.9v-210.6h142.9v23.2H3688.3z"/>
|
||||
<path fill="#6D6E71" d="M4147,2082.4v74h98.4v23.2H4147v90.2h-24.1v-210.6h133.8v23.2H4147z"/>
|
||||
<path fill="#6D6E71" d="M4523.3,2072.8c16.8,9.4,30.2,22.3,40,38.4c9.8,16.2,14.8,33.9,14.8,53.3c0,19.5-4.9,37.4-14.8,53.6 c-9.8,16.3-23.2,29.1-40,38.6c-16.8,9.5-35.3,14.3-55.2,14.3c-20.3,0-38.8-4.7-55.7-14.3c-16.8-9.5-30.2-22.4-40-38.6 c-9.8-16.3-14.8-34.1-14.8-53.6c0-19.5,4.9-37.3,14.8-53.5c9.8-16.2,23.2-29,40-38.3c16.8-9.4,35.4-14,55.7-14 C4488.1,2058.6,4506.5,2063.3,4523.3,2072.8z M4425.2,2092.7c-13.1,7.4-23.6,17.5-31.4,30.1c-7.8,12.6-11.8,26.5-11.8,41.7 c0,15.3,3.9,29.3,11.8,42c7.8,12.7,18.3,22.8,31.4,30.2c13.1,7.4,27.4,11.1,42.9,11.1c15.5,0,29.7-3.7,42.7-11.1 c13-7.4,23.3-17.4,31.1-30.2c7.7-12.7,11.6-26.7,11.6-42s-3.9-29.2-11.6-41.8c-7.7-12.6-18.1-22.6-31.1-30 c-13-7.4-27.2-11.2-42.6-11.2C4452.6,2081.5,4438.3,2085.2,4425.2,2092.7z"/>
|
||||
<path fill="#6D6E71" d="M4854.7,2247.7c-15.7,15.5-37.3,23.3-64.8,23.3c-27.7,0-49.4-7.8-65.1-23.3c-15.7-15.5-23.6-37-23.6-64.6 v-124h24.1v124c0,20.3,5.8,36.1,17.3,47.5c11.6,11.4,27.3,17.1,47.3,17.1c20.1,0,35.8-5.7,47.1-17c11.4-11.3,17-27.2,17-47.7v-124 h24.1v124C4878.2,2210.7,4870.4,2232.2,4854.7,2247.7z"/>
|
||||
<path fill="#6D6E71" d="M5169.5,2269.8l-126.3-169.1v169.1h-24.1v-210.6h25l126.3,169.3v-169.3h23.8v210.6H5169.5z"/>
|
||||
<path fill="#6D6E71" d="M5478.4,2073.1c16.4,9.3,29.4,21.9,38.9,37.9c9.6,16,14.3,33.9,14.3,53.5s-4.8,37.6-14.3,53.6 c-9.5,16.1-22.6,28.7-39.3,37.9c-16.6,9.2-35.2,13.8-55.5,13.8h-84.3v-210.6h85.2C5443.7,2059.2,5462,2063.8,5478.4,2073.1z M5362.3,2246.9h61.4c15.5,0,29.6-3.5,42.3-10.6c12.7-7.1,22.8-16.9,30.2-29.5c7.4-12.5,11.1-26.5,11.1-42 c0-15.5-3.8-29.4-11.3-41.9c-7.5-12.5-17.7-22.3-30.6-29.6c-12.8-7.2-27-10.9-42.6-10.9h-60.5V2246.9z"/>
|
||||
<path fill="#6D6E71" d="M5668.6,2216.6l-23.5,53.2h-25.6l94.4-210.6h25l94.1,210.6H5807l-23.5-53.2H5668.6z M5725.8,2086.6 l-46.9,106.8h94.4L5725.8,2086.6z"/>
|
||||
<path fill="#6D6E71" d="M5991,2082.4v187.4H5967v-187.4h-68.4v-23.2h161.4v23.2H5991z"/>
|
||||
<path fill="#6D6E71" d="M6175.9,2269.8v-210.6h24.1v210.6H6175.9z"/>
|
||||
<path fill="#6D6E71" d="M6493.7,2072.8c16.8,9.4,30.2,22.3,40,38.4c9.8,16.2,14.8,33.9,14.8,53.3c0,19.5-4.9,37.4-14.8,53.6 c-9.8,16.3-23.2,29.1-40,38.6c-16.8,9.5-35.3,14.3-55.2,14.3c-20.3,0-38.8-4.7-55.7-14.3c-16.8-9.5-30.2-22.4-40-38.6 c-9.8-16.3-14.8-34.1-14.8-53.6c0-19.5,4.9-37.3,14.8-53.5c9.8-16.2,23.2-29,40-38.3c16.8-9.4,35.4-14,55.7-14 C6458.5,2058.6,6476.9,2063.3,6493.7,2072.8z M6395.6,2092.7c-13.1,7.4-23.6,17.5-31.4,30.1c-7.8,12.6-11.8,26.5-11.8,41.7 c0,15.3,3.9,29.3,11.8,42c7.8,12.7,18.3,22.8,31.4,30.2c13.1,7.4,27.4,11.1,42.9,11.1c15.5,0,29.7-3.7,42.7-11.1 c13-7.4,23.3-17.4,31.1-30.2c7.7-12.7,11.6-26.7,11.6-42s-3.9-29.2-11.6-41.8c-7.7-12.6-18.1-22.6-31.1-30 c-13-7.4-27.2-11.2-42.6-11.2C6423,2081.5,6408.8,2085.2,6395.6,2092.7z"/>
|
||||
<path fill="#6D6E71" d="M6826.5,2269.8l-126.3-169.1v169.1h-24.1v-210.6h25l126.3,169.3v-169.3h23.8v210.6H6826.5z"/>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-4516.6152" y1="-2338.7222" x2="-4108.4111" y2="-1861.3982" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 5117.8774 -2859.9343)">
|
||||
<stop offset="0" style="stop-color:#F69923"/>
|
||||
<stop offset="0.3123" style="stop-color:#F79A23"/>
|
||||
<stop offset="0.8383" style="stop-color:#E97826"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_1_)" d="M1230.1,13.7c-45.3,26.8-120.6,102.5-210.5,212.3l82.6,155.9c58-82.9,116.9-157.5,176.3-221.2 c4.6-5.1,7-7.5,7-7.5c-2.3,2.5-4.6,5-7,7.5c-19.2,21.2-77.5,89.2-165.5,224.4c84.7-4.2,214.9-21.6,321.1-39.7 c31.6-177-31-258-31-258S1323.4-41.4,1230.1,13.7z"/>
|
||||
<path fill="none" d="M1090.2,903.1c0.6-0.1,1.2-0.2,1.8-0.3l-11.9,1.3c-0.7,0.3-1.4,0.7-2.1,1 C1082.1,904.4,1086.2,903.7,1090.2,903.1z"/>
|
||||
<path fill="none" d="M1005.9,1182.3c-6.7,1.5-13.7,2.7-20.7,3.7C992.3,1185,999.2,1183.8,1005.9,1182.3z"/>
|
||||
<path fill="none" d="M432.9,1808.8c0.9-2.3,1.8-4.7,2.6-7c18.2-48,36.2-94.7,54-140.1c20-51,39.8-100.4,59.3-148.3 c20.6-50.4,40.9-99.2,60.9-146.3c21-49.4,41.7-97,62-142.8c16.5-37.3,32.8-73.4,48.9-108.3c5.4-11.7,10.7-23.2,16-34.6 c10.5-22.7,21-44.8,31.3-66.5c9.5-20,19-39.6,28.3-58.8c3.1-6.4,6.2-12.8,9.3-19.1c0.5-1,1-2,1.5-3.1l-10.2,1.1l-8-15.9 c-0.8,1.6-1.6,3.1-2.4,4.6c-14.5,28.8-28.9,57.9-43.1,87.2c-8.2,16.9-16.4,34-24.6,51c-22.6,47.4-44.8,95.2-66.6,143.3 c-22.1,48.6-43.7,97.5-64.9,146.5c-20.8,48.1-41.3,96.2-61.2,144.2c-20,48-39.5,95.7-58.5,143.2c-19.9,49.5-39.2,98.7-58,147.2 c-4.2,10.9-8.5,21.9-12.7,32.8c-15,39.2-29.7,77.8-44,116l12.7,25.1l11.4-1.2c0.4-1.1,0.8-2.3,1.3-3.4 C396.7,1905.4,414.9,1856.4,432.9,1808.8z"/>
|
||||
<path fill="none" d="M980,1186.8L980,1186.8c0.1,0,0.1,0,0.1-0.1C980.1,1186.8,980.1,1186.8,980,1186.8z"/>
|
||||
<path fill="#BE202E" d="M952.6,1323c-10.6,1.9-21.4,3.8-32.5,5.7c-0.1,0-0.1,0.1-0.2,0.1c5.6-0.8,11.2-1.7,16.6-2.6 C942,1325.2,947.3,1324.1,952.6,1323z"/>
|
||||
<path opacity="0.35" fill="#BE202E" d="M952.6,1323c-10.6,1.9-21.4,3.8-32.5,5.7c-0.1,0-0.1,0.1-0.2,0.1c5.6-0.8,11.2-1.7,16.6-2.6 C942,1325.2,947.3,1324.1,952.6,1323z"/>
|
||||
<path fill="#BE202E" d="M980.3,1186.7C980.2,1186.7,980.2,1186.7,980.3,1186.7c-0.1,0.1-0.2,0.1-0.2,0.1c1.8-0.2,3.5-0.5,5.2-0.8 c7-1,13.9-2.2,20.7-3.7C997.5,1183.8,989,1185.2,980.3,1186.7L980.3,1186.7L980.3,1186.7z"/>
|
||||
<path opacity="0.35" fill="#BE202E" d="M980.3,1186.7C980.2,1186.7,980.2,1186.7,980.3,1186.7c-0.1,0.1-0.2,0.1-0.2,0.1 c1.8-0.2,3.5-0.5,5.2-0.8c7-1,13.9-2.2,20.7-3.7C997.5,1183.8,989,1185.2,980.3,1186.7L980.3,1186.7L980.3,1186.7z"/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="-7537.7339" y1="-2391.4075" x2="-4625.4141" y2="-2391.4075" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 5117.8774 -2859.9343)">
|
||||
<stop offset="0.3233" style="stop-color:#9E2064"/>
|
||||
<stop offset="0.6302" style="stop-color:#C92037"/>
|
||||
<stop offset="0.7514" style="stop-color:#CD2335"/>
|
||||
<stop offset="1" style="stop-color:#E97826"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_2_)" d="M858.6,784.7c25.1-46.9,50.5-92.8,76.2-137.4c26.7-46.4,53.7-91.3,80.9-134.7 c1.6-2.6,3.2-5.2,4.8-7.7c27-42.7,54.2-83.7,81.6-122.9L1019.5,226c-6.2,7.6-12.5,15.3-18.8,23.2c-23.8,29.7-48.6,61.6-73.9,95.5 c-28.6,38.2-58,78.9-87.8,121.7c-27.6,39.5-55.5,80.9-83.5,123.7c-23.8,36.5-47.7,74-71.4,112.5c-0.9,1.4-1.8,2.9-2.6,4.3 l107.5,212.3C811.8,873.6,835.1,828.7,858.6,784.7z"/>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="-7186.1777" y1="-2099.3059" x2="-5450.7183" y2="-2099.3059" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 5117.8774 -2859.9343)">
|
||||
<stop offset="0" style="stop-color:#282662"/>
|
||||
<stop offset="9.548390e-02" style="stop-color:#662E8D"/>
|
||||
<stop offset="0.7882" style="stop-color:#9F2064"/>
|
||||
<stop offset="0.9487" style="stop-color:#CD2032"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_3_)" d="M369,1981c-14.2,39.1-28.5,78.9-42.9,119.6c-0.2,0.6-0.4,1.2-0.6,1.8c-2,5.7-4.1,11.5-6.1,17.2 c-9.7,27.4-18,52.1-37.3,108.2c31.7,14.5,57.1,52.5,81.1,95.6c-2.6-44.7-21-86.6-56.2-119.1c156.1,7,290.6-32.4,360.1-146.6 c6.2-10.2,11.9-20.9,17-32.2c-31.6,40.1-70.8,57.1-144.5,53c-0.2,0.1-0.3,0.1-0.5,0.2c0.2-0.1,0.3-0.1,0.5-0.2 c108.6-48.6,163.1-95.3,211.2-172.6c11.4-18.3,22.5-38.4,33.8-60.6c-94.9,97.5-205,125.3-320.9,104.2l-86.9,9.5 C374.4,1966.3,371.7,1973.6,369,1981z"/>
|
||||
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="-7374.1626" y1="-2418.5454" x2="-4461.8428" y2="-2418.5454" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 5117.8774 -2859.9343)">
|
||||
<stop offset="0.3233" style="stop-color:#9E2064"/>
|
||||
<stop offset="0.6302" style="stop-color:#C92037"/>
|
||||
<stop offset="0.7514" style="stop-color:#CD2335"/>
|
||||
<stop offset="1" style="stop-color:#E97826"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_4_)" d="M409.6,1786.3c18.8-48.5,38.1-97.7,58-147.2c19-47.4,38.5-95.2,58.5-143.2 c20-48,40.4-96.1,61.2-144.2c21.2-49,42.9-97.8,64.9-146.5c21.8-48.1,44-95.9,66.6-143.3c8.1-17.1,16.3-34.1,24.6-51 c14.2-29.3,28.6-58.4,43.1-87.2c0.8-1.6,1.6-3.1,2.4-4.6L681.4,706.8c-1.8,2.9-3.5,5.8-5.3,8.6c-25.1,40.9-50,82.7-74.4,125.4 c-24.7,43.1-49,87.1-72.7,131.7c-20,37.6-39.6,75.6-58.6,113.9c-3.8,7.8-7.6,15.5-11.3,23.2c-23.4,48.2-44.6,94.8-63.7,139.5 c-21.7,50.7-40.7,99.2-57.5,145.1c-11,30.2-21,59.4-30.1,87.4c-7.5,24-14.7,47.9-21.5,71.8c-16,56.3-29.9,112.4-41.2,168.3 L353,1935.1c14.3-38.1,28.9-76.8,44-116C401.1,1808.2,405.4,1797.3,409.6,1786.3z"/>
|
||||
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="-7161.7642" y1="-2379.1431" x2="-5631.2524" y2="-2379.1431" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 5117.8774 -2859.9343)">
|
||||
<stop offset="0" style="stop-color:#282662"/>
|
||||
<stop offset="9.548390e-02" style="stop-color:#662E8D"/>
|
||||
<stop offset="0.7882" style="stop-color:#9F2064"/>
|
||||
<stop offset="0.9487" style="stop-color:#CD2032"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_5_)" d="M243.5,1729.4c-13.6,68.2-23.2,136.2-28,203.8c-0.2,2.4-0.4,4.7-0.5,7.1 c-33.7-54-124-106.8-123.8-106.2c64.6,93.7,113.7,186.7,120.9,278c-34.6,7.1-82-3.2-136.8-23.3c57.1,52.5,100,67,116.7,70.9 c-52.5,3.3-107.1,39.3-162.1,80.8c80.5-32.8,145.5-45.8,192.1-35.3C148.1,2414.2,74.1,2645,0,2890c22.7-6.7,36.2-21.9,43.9-42.6 c13.2-44.4,100.8-335.6,238-718.2c3.9-10.9,7.8-21.8,11.8-32.9c1.1-3,2.2-6.1,3.3-9.2c14.5-40.1,29.5-81.1,45.1-122.9 c3.5-9.5,7.1-19,10.7-28.6c0.1-0.2,0.1-0.4,0.2-0.6l-107.9-213.2C244.6,1724.4,244,1726.9,243.5,1729.4z"/>
|
||||
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="-7374.1626" y1="-2117.1309" x2="-4461.8428" y2="-2117.1309" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 5117.8774 -2859.9343)">
|
||||
<stop offset="0.3233" style="stop-color:#9E2064"/>
|
||||
<stop offset="0.6302" style="stop-color:#C92037"/>
|
||||
<stop offset="0.7514" style="stop-color:#CD2335"/>
|
||||
<stop offset="1" style="stop-color:#E97826"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_6_)" d="M805.6,937c-3.1,6.3-6.2,12.7-9.3,19.1c-9.3,19.2-18.8,38.8-28.3,58.8 c-10.3,21.7-20.7,43.9-31.3,66.5c-5.3,11.4-10.6,22.9-16,34.6c-16.1,35-32.4,71.1-48.9,108.3c-20.3,45.8-41,93.4-62,142.8 c-20,47.1-40.3,95.9-60.9,146.3c-19.5,47.9-39.3,97.3-59.3,148.3c-17.8,45.4-35.9,92.1-54,140.1c-0.9,2.3-1.8,4.7-2.6,7 c-18,47.6-36.2,96.6-54.6,146.8c-0.4,1.1-0.8,2.3-1.3,3.4l86.9-9.5c-1.7-0.3-3.5-0.5-5.2-0.9c103.9-13,242.1-90.6,331.4-186.5 c41.1-44.2,78.5-96.3,113-157.3c25.7-45.4,49.8-95.8,72.8-151.5c20.1-48.7,39.4-101.4,58-158.6c-23.9,12.6-51.2,21.8-81.4,28.2 c-5.3,1.1-10.7,2.2-16.1,3.1c-5.5,1-11,1.8-16.6,2.6l0,0l0,0c0.1,0,0.1-0.1,0.2-0.1c96.9-37.3,158-109.2,202.4-197.4 c-25.5,17.4-66.9,40.1-116.6,51.1c-6.7,1.5-13.7,2.7-20.7,3.7c-1.7,0.3-3.5,0.6-5.2,0.8l0,0l0,0c0.1,0,0.1,0,0.1-0.1 c0,0,0.1,0,0.1,0l0,0c33.6-14.1,62-29.8,86.6-48.4c5.3-4,10.4-8.1,15.3-12.3c7.5-6.5,14.7-13.3,21.5-20.5c4.4-4.6,8.6-9.3,12.7-14.2 c9.6-11.5,18.7-23.9,27.1-37.3c2.6-4.1,5.1-8.3,7.6-12.6c3.2-6.2,6.3-12.3,9.3-18.3c13.5-27.2,24.4-51.5,33-72.8 c4.3-10.6,8.1-20.5,11.3-29.7c1.3-3.7,2.5-7.2,3.7-10.6c3.4-10.2,6.2-19.3,8.4-27.3c3.3-12,5.3-21.5,6.4-28.4l0,0l0,0 c-3.3,2.6-7.1,5.2-11.3,7.7c-29.3,17.5-79.5,33.4-119.9,40.8l79.8-8.8l-79.8,8.8c-0.6,0.1-1.2,0.2-1.8,0.3c-4,0.7-8.1,1.3-12.2,2 c0.7-0.3,1.4-0.7,2.1-1l-273,29.9C806.6,935,806.1,936,805.6,937z"/>
|
||||
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="-7554.8232" y1="-2132.0981" x2="-4642.5034" y2="-2132.0981" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 5117.8774 -2859.9343)">
|
||||
<stop offset="0.3233" style="stop-color:#9E2064"/>
|
||||
<stop offset="0.6302" style="stop-color:#C92037"/>
|
||||
<stop offset="0.7514" style="stop-color:#CD2335"/>
|
||||
<stop offset="1" style="stop-color:#E97826"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_7_)" d="M1112.9,385.1c-24.3,37.3-50.8,79.6-79.4,127.5c-1.5,2.5-3,5.1-4.5,7.6 c-24.6,41.5-50.8,87.1-78.3,137c-23.8,43.1-48.5,89.3-74.3,139c-22.4,43.3-45.6,89.2-69.4,137.8l273-29.9 c79.5-36.6,115.1-69.7,149.6-117.6c9.2-13.2,18.4-27,27.5-41.3c28-43.8,55.6-92,80.1-139.9c23.7-46.3,44.7-92.2,60.7-133.5 c10.2-26.3,18.4-50.8,24.1-72.3c5-19,8.9-36.9,11.9-54.1C1327.9,363.5,1197.6,380.9,1112.9,385.1z"/>
|
||||
<path fill="#BE202E" d="M936.5,1326.1c-5.5,1-11,1.8-16.6,2.6l0,0C925.5,1328,931,1327.1,936.5,1326.1z"/>
|
||||
<path opacity="0.35" fill="#BE202E" d="M936.5,1326.1c-5.5,1-11,1.8-16.6,2.6l0,0C925.5,1328,931,1327.1,936.5,1326.1z"/>
|
||||
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="-7374.1626" y1="-2027.484" x2="-4461.8433" y2="-2027.484" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 5117.8774 -2859.9343)">
|
||||
<stop offset="0.3233" style="stop-color:#9E2064"/>
|
||||
<stop offset="0.6302" style="stop-color:#C92037"/>
|
||||
<stop offset="0.7514" style="stop-color:#CD2335"/>
|
||||
<stop offset="1" style="stop-color:#E97826"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_8_)" d="M936.5,1326.1c-5.5,1-11,1.8-16.6,2.6l0,0C925.5,1328,931,1327.1,936.5,1326.1z"/>
|
||||
<path fill="#BE202E" d="M980,1186.8c1.8-0.2,3.5-0.5,5.2-0.8C983.5,1186.3,981.8,1186.6,980,1186.8L980,1186.8z"/>
|
||||
<path opacity="0.35" fill="#BE202E" d="M980,1186.8c1.8-0.2,3.5-0.5,5.2-0.8C983.5,1186.3,981.8,1186.6,980,1186.8L980,1186.8z"/>
|
||||
<linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="-7374.1626" y1="-2037.7417" x2="-4461.8433" y2="-2037.7417" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 5117.8774 -2859.9343)">
|
||||
<stop offset="0.3233" style="stop-color:#9E2064"/>
|
||||
<stop offset="0.6302" style="stop-color:#C92037"/>
|
||||
<stop offset="0.7514" style="stop-color:#CD2335"/>
|
||||
<stop offset="1" style="stop-color:#E97826"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_9_)" d="M980,1186.8c1.8-0.2,3.5-0.5,5.2-0.8C983.5,1186.3,981.8,1186.6,980,1186.8L980,1186.8z"/>
|
||||
<path fill="#BE202E" d="M980.2,1186.7C980.2,1186.7,980.2,1186.7,980.2,1186.7L980.2,1186.7L980.2,1186.7L980.2,1186.7 C980.2,1186.7,980.2,1186.7,980.2,1186.7z"/>
|
||||
<path opacity="0.35" fill="#BE202E" d="M980.2,1186.7C980.2,1186.7,980.2,1186.7,980.2,1186.7L980.2,1186.7L980.2,1186.7 L980.2,1186.7C980.2,1186.7,980.2,1186.7,980.2,1186.7z"/>
|
||||
<linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="-5738.0635" y1="-2039.799" x2="-5094.3457" y2="-2039.799" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 5117.8774 -2859.9343)">
|
||||
<stop offset="0.3233" style="stop-color:#9E2064"/>
|
||||
<stop offset="0.6302" style="stop-color:#C92037"/>
|
||||
<stop offset="0.7514" style="stop-color:#CD2335"/>
|
||||
<stop offset="1" style="stop-color:#E97826"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_10_)" d="M980.2,1186.7C980.2,1186.7,980.2,1186.7,980.2,1186.7L980.2,1186.7L980.2,1186.7L980.2,1186.7 C980.2,1186.7,980.2,1186.7,980.2,1186.7z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 19 KiB |
89
ui/public/assets/feather.svg
Normal file
89
ui/public/assets/feather.svg
Normal file
@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Feather" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 2392.5 4226.6" enable-background="new 0 0 2392.5 4226.6" xml:space="preserve">
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-5167.0962" y1="697.5549" x2="-4570.1162" y2="1395.619" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 3144.8108 -4619.2983)">
|
||||
<stop offset="0" style="stop-color:#F69923"/>
|
||||
<stop offset="0.3123" style="stop-color:#F79A23"/>
|
||||
<stop offset="0.8383" style="stop-color:#E97826"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_1_)" d="M1798.9,20.1C1732.6,59.2,1622.5,170,1491,330.5l120.8,228c84.8-121.3,170.9-230.4,257.8-323.6 c6.7-7.4,10.2-10.9,10.2-10.9c-3.4,3.6-6.8,7.3-10.2,10.9c-28.1,31-113.4,130.5-242.1,328.1c123.9-6.2,314.3-31.5,469.6-58.1 c46.2-258.8-45.3-377.3-45.3-377.3S1935.5-60.6,1798.9,20.1z"/>
|
||||
<path fill="none" d="M1594.4,1320.7c0.9-0.2,1.8-0.3,2.7-0.5l-17.4,1.9c-1.1,0.5-2,1-3.1,1.4 C1582.6,1322.6,1588.5,1321.6,1594.4,1320.7z"/>
|
||||
<path fill="none" d="M1471.1,1729.1c-9.9,2.2-20,3.9-30.2,5.4C1451.1,1733,1461.2,1731.2,1471.1,1729.1z"/>
|
||||
<path fill="none" d="M633.1,2645.2c1.3-3.4,2.6-6.8,3.8-10.2c26.6-70.2,52.9-138.4,79-204.9c29.3-74.6,58.2-146.8,86.8-216.8 c30.1-73.8,59.8-145.1,89.1-214c30.7-72.3,61-141.9,90.7-208.9c24.2-54.5,48-107.3,71.5-158.4c7.8-17,15.6-33.9,23.4-50.6 c15.4-33.1,30.7-65.6,45.7-97.3c13.9-29.3,27.7-57.9,41.4-86c4.5-9.4,9.1-18.6,13.6-27.9c0.7-1.5,1.5-3,2.2-4.5l-14.8,1.6 l-11.8-23.2c-1.1,2.3-2.3,4.5-3.5,6.8c-21.2,42.1-42.2,84.6-63,127.5c-12,24.8-24,49.7-35.9,74.7c-33,69.3-65.5,139.2-97.4,209.6 c-32.3,71.1-63.9,142.6-94.9,214.2c-30.5,70.3-60.3,140.7-89.6,210.9c-29.2,70.1-57.7,140-85.6,209.4 c-29.1,72.5-57.4,144.3-84.8,215.3c-6.2,16-12.4,32-18.5,48c-22,57.3-43.4,113.8-64.3,169.6l18.6,36.7l16.6-1.8 c0.6-1.7,1.2-3.4,1.8-5C580.1,2786.5,606.7,2714.9,633.1,2645.2z"/>
|
||||
<path fill="none" d="M1433.2,1735.7L1433.2,1735.7c0.1,0,0.1-0.1,0.2-0.1C1433.4,1735.6,1433.3,1735.6,1433.2,1735.7z"/>
|
||||
<path fill="#BE202E" d="M1393.2,1934.8c-15.4,2.8-31.3,5.5-47.6,8.3c-0.1,0-0.2,0.1-0.3,0.1c8.2-1.2,16.3-2.4,24.3-3.8 C1377.6,1938,1385.4,1936.5,1393.2,1934.8z"/>
|
||||
<path opacity="0.35" fill="#BE202E" d="M1393.2,1934.8c-15.4,2.8-31.3,5.5-47.6,8.3c-0.1,0-0.2,0.1-0.3,0.1 c8.2-1.2,16.3-2.4,24.3-3.8C1377.6,1938,1385.4,1936.5,1393.2,1934.8z"/>
|
||||
<path fill="#BE202E" d="M1433.6,1735.5c0,0-0.1,0-0.1,0.1c-0.1,0-0.1,0.1-0.2,0.1c2.6-0.3,5.1-0.8,7.6-1.1 c10.3-1.5,20.4-3.3,30.2-5.4C1458.8,1731.2,1446.3,1733.4,1433.6,1735.5L1433.6,1735.5L1433.6,1735.5z"/>
|
||||
<path opacity="0.35" fill="#BE202E" d="M1433.6,1735.5c0,0-0.1,0-0.1,0.1c-0.1,0-0.1,0.1-0.2,0.1c2.6-0.3,5.1-0.8,7.6-1.1 c10.3-1.5,20.4-3.3,30.2-5.4C1458.8,1731.2,1446.3,1733.4,1433.6,1735.5L1433.6,1735.5L1433.6,1735.5z"/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="-9585.3418" y1="620.5048" x2="-5326.209" y2="620.5048" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 3144.8108 -4619.2983)">
|
||||
<stop offset="0.3233" style="stop-color:#9E2064"/>
|
||||
<stop offset="0.6302" style="stop-color:#C92037"/>
|
||||
<stop offset="0.7514" style="stop-color:#CD2335"/>
|
||||
<stop offset="1" style="stop-color:#E97826"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_2_)" d="M1255.7,1147.6c36.7-68.6,73.9-135.7,111.5-201c39-67.8,78.5-133.6,118.4-197c2.3-3.7,4.7-7.5,7-11.3 c39.4-62.4,79.2-122.4,119.3-179.8l-120.8-228c-9.1,11.1-18.2,22.4-27.5,33.9c-34.8,43.4-71,90.1-108.1,139.6 c-41.8,55.8-84.8,115.4-128.5,177.9c-40.3,57.8-81.2,118.3-122.1,180.9c-34.8,53.3-69.8,108.2-104.5,164.5c-1.3,2.1-2.6,4.2-3.9,6.3 l157.2,310.5C1187.3,1277.6,1221.3,1212,1255.7,1147.6z"/>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="-9071.207" y1="1047.6898" x2="-6533.1782" y2="1047.6898" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 3144.8108 -4619.2983)">
|
||||
<stop offset="0" style="stop-color:#282662"/>
|
||||
<stop offset="9.548390e-02" style="stop-color:#662E8D"/>
|
||||
<stop offset="0.7882" style="stop-color:#9F2064"/>
|
||||
<stop offset="0.9487" style="stop-color:#CD2032"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_3_)" d="M539.7,2897.1c-20.8,57.2-41.7,115.4-62.7,174.9c-0.3,0.9-0.6,1.7-0.9,2.6c-3,8.4-5.9,16.8-8.9,25.2 c-14.1,40.1-26.4,76.2-54.5,158.3c46.3,21.1,83.5,76.7,118.7,139.8c-3.7-65.3-30.8-126.7-82.1-174.2 c228.3,10.3,425-47.4,526.7-214.3c9.1-14.9,17.4-30.5,24.9-47.2c-46.2,58.6-103.5,83.5-211.4,77.4c-0.2,0.1-0.5,0.2-0.7,0.3 c0.2-0.1,0.5-0.2,0.7-0.3c158.8-71.1,238.5-139.3,308.9-252.4c16.7-26.8,32.9-56.1,49.5-88.6C1009,2841.2,848.1,2881.8,678.6,2851 l-127.1,13.9C547.5,2875.6,543.6,2886.3,539.7,2897.1z"/>
|
||||
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="-9346.126" y1="580.817" x2="-5086.9941" y2="580.817" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 3144.8108 -4619.2983)">
|
||||
<stop offset="0.3233" style="stop-color:#9E2064"/>
|
||||
<stop offset="0.6302" style="stop-color:#C92037"/>
|
||||
<stop offset="0.7514" style="stop-color:#CD2335"/>
|
||||
<stop offset="1" style="stop-color:#E97826"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_4_)" d="M599,2612.4c27.5-71,55.8-142.8,84.8-215.3c27.8-69.4,56.4-139.2,85.6-209.4 c29.2-70.2,59.1-140.5,89.6-210.9c31-71.6,62.7-143.1,94.9-214.2c31.9-70.3,64.4-140.3,97.4-209.6c11.9-25,23.9-49.9,35.9-74.7 c20.8-42.9,41.8-85.4,63-127.5c1.1-2.3,2.3-4.5,3.5-6.8l-157.2-310.5c-2.6,4.2-5.1,8.4-7.7,12.6c-36.6,59.8-73.1,121-108.9,183.5 c-36.2,63.1-71.7,127.4-106.4,192.6c-29.3,55-57.9,110.5-85.7,166.5c-5.6,11.4-11.1,22.6-16.6,33.9 c-34.3,70.5-65.2,138.6-93.2,204.1c-31.7,74.2-59.6,145.1-84,212.3c-16.1,44.2-30.7,86.9-44.1,127.9c-11,35-21.5,70.1-31.4,105 c-23.5,82.3-43.7,164.4-60.3,246.2L516.2,2830c20.9-55.8,42.3-112.3,64.3-169.6C586.6,2644.5,592.8,2628.4,599,2612.4z"/>
|
||||
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="-9035.5029" y1="638.4408" x2="-6797.2012" y2="638.4408" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 3144.8108 -4619.2983)">
|
||||
<stop offset="0" style="stop-color:#282662"/>
|
||||
<stop offset="9.548390e-02" style="stop-color:#662E8D"/>
|
||||
<stop offset="0.7882" style="stop-color:#9F2064"/>
|
||||
<stop offset="0.9487" style="stop-color:#CD2032"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_5_)" d="M356.1,2529.2c-19.8,99.8-33.9,199.2-41,298c-0.2,3.5-0.6,6.9-0.8,10.4 c-49.3-79-181.3-156.1-181-155.4c94.5,137,166.2,273,176.9,406.5c-50.6,10.4-119.9-4.6-200-34.1c83.5,76.7,146.2,97.9,170.6,103.6 c-76.7,4.8-156.6,57.5-237.1,118.2c117.7-48,212.8-67,280.9-51.6C216.6,3530.6,108.3,3868.2,0,4226.6c33.2-9.8,53-32.1,64.1-62.3 c19.3-64.9,147.4-490.7,348.1-1050.4c5.7-15.9,11.5-31.9,17.3-48c1.6-4.5,3.3-9,4.9-13.4c21.2-58.7,43.2-118.6,65.9-179.7 c5.2-13.9,10.4-27.8,15.6-41.8c0.1-0.3,0.2-0.6,0.3-0.8l-157.8-311.8C357.7,2521.9,356.8,2525.5,356.1,2529.2z"/>
|
||||
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="-9346.126" y1="1021.6218" x2="-5086.9941" y2="1021.6218" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 3144.8108 -4619.2983)">
|
||||
<stop offset="0.3233" style="stop-color:#9E2064"/>
|
||||
<stop offset="0.6302" style="stop-color:#C92037"/>
|
||||
<stop offset="0.7514" style="stop-color:#CD2335"/>
|
||||
<stop offset="1" style="stop-color:#E97826"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_6_)" d="M1178.1,1370.3c-4.5,9.2-9,18.5-13.6,27.9c-13.6,28.1-27.4,56.7-41.4,86 c-15.1,31.7-30.3,64.1-45.7,97.3c-7.8,16.7-15.5,33.5-23.4,50.6c-23.5,51.1-47.3,103.9-71.5,158.4c-29.7,67-60,136.6-90.7,208.9 c-29.3,68.9-59,140.2-89.1,214c-28.6,70-57.5,142.3-86.8,216.8c-26.1,66.5-52.4,134.7-79,204.9c-1.3,3.4-2.6,6.8-3.8,10.2 c-26.4,69.7-53,141.3-79.8,214.7c-0.6,1.7-1.2,3.4-1.8,5l127.1-13.9c-2.5-0.5-5.1-0.8-7.6-1.3c152-18.9,354-132.5,484.6-272.7 c60.2-64.6,114.8-140.8,165.3-230c37.6-66.4,72.9-140,106.5-221.5c29.4-71.2,57.6-148.3,84.8-231.9c-34.9,18.4-74.9,31.9-119,41.3 c-7.7,1.6-15.6,3.2-23.6,4.6c-8,1.4-16.1,2.7-24.3,3.8l0,0l0,0c0.1,0,0.2-0.1,0.3-0.1c141.7-54.5,231.1-159.8,296.1-288.7 c-37.3,25.4-97.9,58.7-170.5,74.7c-9.9,2.2-20,3.9-30.2,5.4c-2.6,0.4-5.1,0.8-7.6,1.1l0,0l0,0c0.1,0,0.1-0.1,0.2-0.1 c0,0,0.1,0,0.1-0.1l0,0c49.2-20.6,90.7-43.6,126.7-70.8c7.7-5.8,15.2-11.8,22.4-18.1c11-9.5,21.4-19.5,31.4-30 c6.4-6.7,12.6-13.6,18.6-20.8c14.1-16.8,27.3-34.9,39.7-54.6c3.8-6,7.5-12.1,11.2-18.4c4.7-9.1,9.2-18,13.6-26.8 c19.8-39.8,35.6-75.3,48.2-106.5c6.3-15.6,11.8-30,16.5-43.4c1.9-5.3,3.7-10.5,5.4-15.5c5-15,9.1-28.3,12.3-40 c4.8-17.5,7.7-31.4,9.3-41.5l0,0l0,0c-4.8,3.8-10.3,7.6-16.5,11.3c-42.8,25.6-116.2,48.8-175.4,59.7l116.7-12.8l-116.7,12.8 c-0.9,0.2-1.8,0.3-2.7,0.5c-5.9,1-11.9,1.9-17.9,2.9c1.1-0.5,2-1,3.1-1.4l-399.3,43.8C1179.6,1367.4,1178.9,1368.8,1178.1,1370.3z"/>
|
||||
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="-9610.334" y1="999.733" x2="-5351.2017" y2="999.733" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 3144.8108 -4619.2983)">
|
||||
<stop offset="0.3233" style="stop-color:#9E2064"/>
|
||||
<stop offset="0.6302" style="stop-color:#C92037"/>
|
||||
<stop offset="0.7514" style="stop-color:#CD2335"/>
|
||||
<stop offset="1" style="stop-color:#E97826"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_7_)" d="M1627.6,563.1c-35.5,54.5-74.3,116.4-116,186.5c-2.2,3.6-4.4,7.4-6.6,11.1 c-36,60.7-74.3,127.3-114.5,200.3c-34.8,63-71,130.6-108.6,203.3c-32.8,63.3-66.7,130.5-101.5,201.6l399.3-43.8 c116.3-53.5,168.3-101.9,218.8-171.9c13.4-19.3,26.9-39.5,40.3-60.4c41-64,81.2-134.5,117.2-204.6c34.7-67.7,65.3-134.8,88.8-195.3 c14.9-38.5,26.9-74.3,35.2-105.7c7.3-27.7,13-54,17.4-79.1C1941.9,531.6,1751.5,557,1627.6,563.1z"/>
|
||||
<path fill="#BE202E" d="M1369.6,1939.4c-8,1.4-16.1,2.7-24.3,3.8l0,0C1353.5,1942.1,1361.6,1940.8,1369.6,1939.4z"/>
|
||||
<path opacity="0.35" fill="#BE202E" d="M1369.6,1939.4c-8,1.4-16.1,2.7-24.3,3.8l0,0C1353.5,1942.1,1361.6,1940.8,1369.6,1939.4z"/>
|
||||
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="-9346.126" y1="1152.7261" x2="-5086.9941" y2="1152.7261" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 3144.8108 -4619.2983)">
|
||||
<stop offset="0.3233" style="stop-color:#9E2064"/>
|
||||
<stop offset="0.6302" style="stop-color:#C92037"/>
|
||||
<stop offset="0.7514" style="stop-color:#CD2335"/>
|
||||
<stop offset="1" style="stop-color:#E97826"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_8_)" d="M1369.6,1939.4c-8,1.4-16.1,2.7-24.3,3.8l0,0C1353.5,1942.1,1361.6,1940.8,1369.6,1939.4z"/>
|
||||
<path fill="#BE202E" d="M1433.2,1735.7c2.6-0.3,5.1-0.8,7.6-1.1C1438.3,1734.9,1435.8,1735.3,1433.2,1735.7L1433.2,1735.7z"/>
|
||||
<path opacity="0.35" fill="#BE202E" d="M1433.2,1735.7c2.6-0.3,5.1-0.8,7.6-1.1C1438.3,1734.9,1435.8,1735.3,1433.2,1735.7 L1433.2,1735.7z"/>
|
||||
<linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="-9346.126" y1="1137.7247" x2="-5086.9941" y2="1137.7247" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 3144.8108 -4619.2983)">
|
||||
<stop offset="0.3233" style="stop-color:#9E2064"/>
|
||||
<stop offset="0.6302" style="stop-color:#C92037"/>
|
||||
<stop offset="0.7514" style="stop-color:#CD2335"/>
|
||||
<stop offset="1" style="stop-color:#E97826"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_9_)" d="M1433.2,1735.7c2.6-0.3,5.1-0.8,7.6-1.1C1438.3,1734.9,1435.8,1735.3,1433.2,1735.7L1433.2,1735.7z"/>
|
||||
<path fill="#BE202E" d="M1433.5,1735.6c0,0,0.1,0,0.1-0.1l0,0l0,0l0,0C1433.6,1735.5,1433.5,1735.5,1433.5,1735.6z"/>
|
||||
<path opacity="0.35" fill="#BE202E" d="M1433.5,1735.6c0,0,0.1,0,0.1-0.1l0,0l0,0l0,0C1433.6,1735.5,1433.5,1735.5,1433.5,1735.6z"/>
|
||||
<linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="-6953.4072" y1="1134.7161" x2="-6011.9995" y2="1134.7161" gradientTransform="matrix(0.4226 -0.9063 0.9063 0.4226 3144.8108 -4619.2983)">
|
||||
<stop offset="0.3233" style="stop-color:#9E2064"/>
|
||||
<stop offset="0.6302" style="stop-color:#C92037"/>
|
||||
<stop offset="0.7514" style="stop-color:#CD2335"/>
|
||||
<stop offset="1" style="stop-color:#E97826"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_10_)" d="M1433.5,1735.6c0,0,0.1,0,0.1-0.1l0,0l0,0l0,0C1433.6,1735.5,1433.5,1735.5,1433.5,1735.6z"/>
|
||||
<path fill="#6D6E71" d="M2218.7,387v11.7h27.4v77.4h12.7v-77.4h27.6V387H2218.7z M2377,387l-30.6,62.2l-30.8-62.2h-15.3v89.1h11.7 v-70.7l30.3,61.3h8.1l30.3-61.3v70.7h11.7V387H2377z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
1
ui/public/config.json
vendored
1
ui/public/config.json
vendored
@ -17,6 +17,7 @@
|
||||
"logo": "assets/logo.svg",
|
||||
"minilogo": "assets/mini-logo.svg",
|
||||
"banner": "assets/banner.svg",
|
||||
"favicon": "cloud.ico",
|
||||
"error": {
|
||||
"403": "assets/403.png",
|
||||
"404": "assets/404.png",
|
||||
|
||||
1169
ui/public/css/apache-theme.css
Normal file
1169
ui/public/css/apache-theme.css
Normal file
File diff suppressed because it is too large
Load Diff
1592
ui/public/css/dark-theme.css
Normal file
1592
ui/public/css/dark-theme.css
Normal file
File diff suppressed because it is too large
Load Diff
8
ui/public/index.html
vendored
8
ui/public/index.html
vendored
@ -54,12 +54,4 @@
|
||||
<div class="loader"></div>
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript">
|
||||
fetch('./config.json?ts=' + Date.now())
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById("favicon").setAttribute("href", data.loginFavicon);
|
||||
document.getElementById("title").innerHTML = data.loginTitle;
|
||||
}).catch((err) => {});
|
||||
</script>
|
||||
</html>
|
||||
|
||||
@ -88,10 +88,13 @@ export function login (arg) {
|
||||
})
|
||||
}
|
||||
|
||||
export function logout () {
|
||||
message.destroy()
|
||||
notification.destroy()
|
||||
return postAPI('logout')
|
||||
export async function logout () {
|
||||
const result = await postAPI('logout').finally(() => {
|
||||
sourceToken.cancel()
|
||||
message.destroy()
|
||||
notification.destroy()
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
export function oauthlogin (arg) {
|
||||
|
||||
@ -80,6 +80,8 @@ import { mapActions, mapGetters } from 'vuex'
|
||||
import ResourceIcon from '@/components/view/ResourceIcon'
|
||||
import eventBus from '@/config/eventBus'
|
||||
import { SERVER_MANAGER } from '@/store/mutation-types'
|
||||
import { sourceToken } from '@/utils/request'
|
||||
import { applyCustomGuiTheme } from '@/utils/guiTheme'
|
||||
|
||||
export default {
|
||||
name: 'UserMenu',
|
||||
@ -178,7 +180,9 @@ export default {
|
||||
}
|
||||
},
|
||||
handleLogout () {
|
||||
return this.Logout({}).then(() => {
|
||||
this.Logout({}).finally(async () => {
|
||||
sourceToken.init()
|
||||
await applyCustomGuiTheme(null, null)
|
||||
this.$router.push('/user/login')
|
||||
}).catch(err => {
|
||||
this.$message.error({
|
||||
|
||||
@ -43,6 +43,9 @@ import {
|
||||
} from './utils/plugins'
|
||||
import { VueAxios } from './utils/request'
|
||||
import directives from './utils/directives'
|
||||
import Cookies from 'js-cookie'
|
||||
import { api } from '@/api'
|
||||
import { applyCustomGuiTheme } from './utils/guiTheme'
|
||||
|
||||
vueApp.use(VueAxios, router)
|
||||
vueApp.use(pollJobPlugin)
|
||||
@ -89,7 +92,7 @@ fetch('config.json?ts=' + Date.now())
|
||||
}
|
||||
return response.json()
|
||||
})
|
||||
.then(config => {
|
||||
.then(async config => {
|
||||
vueProps.$config = config
|
||||
let baseUrl = config.apiBase
|
||||
if (config.multipleServer) {
|
||||
@ -98,6 +101,19 @@ fetch('config.json?ts=' + Date.now())
|
||||
|
||||
vueProps.axios.defaults.baseURL = baseUrl
|
||||
|
||||
const userid = Cookies.get('userid')
|
||||
let accountid = null
|
||||
let domainid = null
|
||||
|
||||
if (userid !== undefined && Cookies.get('sessionkey')) {
|
||||
await api('listUsers', { userid: userid }).then(response => {
|
||||
accountid = response.listusersresponse.user[0].accountid
|
||||
domainid = response.listusersresponse.user[0].domainid
|
||||
})
|
||||
}
|
||||
|
||||
await applyCustomGuiTheme(accountid, domainid)
|
||||
|
||||
loadLanguageAsync().then(() => {
|
||||
vueApp.use(store)
|
||||
.use(router)
|
||||
|
||||
@ -47,6 +47,10 @@ import {
|
||||
LATEST_CS_VERSION
|
||||
} from '@/store/mutation-types'
|
||||
|
||||
import {
|
||||
applyCustomGuiTheme
|
||||
} from '@/utils/guiTheme'
|
||||
|
||||
const user = {
|
||||
state: {
|
||||
token: '',
|
||||
@ -243,7 +247,6 @@ const user = {
|
||||
const latestVersion = vueProps.$localStorage.get(LATEST_CS_VERSION, { version: '', fetchedTs: 0 })
|
||||
commit('SET_LATEST_VERSION', latestVersion)
|
||||
notification.destroy()
|
||||
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
@ -406,6 +409,7 @@ const user = {
|
||||
|
||||
getAPI('listUsers', { id: Cookies.get('userid'), showicon: true }).then(response => {
|
||||
const result = response.listusersresponse.user[0]
|
||||
applyCustomGuiTheme(result.accountid, result.domainid)
|
||||
commit('SET_INFO', result)
|
||||
commit('SET_NAME', result.firstname + ' ' + result.lastname)
|
||||
commit('SET_AVATAR', result.icon?.base64image || '')
|
||||
|
||||
100
ui/src/utils/guiTheme.js
Normal file
100
ui/src/utils/guiTheme.js
Normal file
@ -0,0 +1,100 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
import { vueProps } from '@/vue-app'
|
||||
import { api } from '@/api'
|
||||
|
||||
export async function applyCustomGuiTheme (accountid, domainid) {
|
||||
await fetch('config.json').then(response => response.json()).then(config => {
|
||||
vueProps.$config = config
|
||||
})
|
||||
|
||||
let guiTheme
|
||||
|
||||
if (accountid != null) {
|
||||
guiTheme = await fetchGuiTheme({ accountid: accountid })
|
||||
}
|
||||
|
||||
if (guiTheme === undefined && domainid != null) {
|
||||
guiTheme = await fetchGuiTheme({ domainid: domainid })
|
||||
}
|
||||
|
||||
if (guiTheme === undefined) {
|
||||
guiTheme = await fetchGuiTheme({ commonname: window.location.hostname })
|
||||
}
|
||||
|
||||
if (guiTheme === undefined) {
|
||||
guiTheme = await fetchGuiTheme({ listonlydefaulttheme: true })
|
||||
}
|
||||
|
||||
await applyDynamicCustomization(guiTheme)
|
||||
}
|
||||
|
||||
async function fetchGuiTheme (params) {
|
||||
return await api('listGuiThemes', params).then(response => {
|
||||
if (response.listguithemesresponse.guiThemes) {
|
||||
return response.listguithemesresponse.guiThemes[0]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function applyDynamicCustomization (response) {
|
||||
let jsonConfig
|
||||
|
||||
if (response?.jsonconfiguration) {
|
||||
jsonConfig = JSON.parse(response?.jsonconfiguration)
|
||||
}
|
||||
|
||||
// Sets custom GUI fields only if is not nullish.
|
||||
vueProps.$config.appTitle = jsonConfig?.appTitle ?? vueProps.$config.appTitle
|
||||
vueProps.$config.footer = jsonConfig?.footer ?? vueProps.$config.footer
|
||||
vueProps.$config.loginFooter = jsonConfig?.loginFooter ?? vueProps.$config.loginFooter
|
||||
vueProps.$config.logo = jsonConfig?.logo ?? vueProps.$config.logo
|
||||
vueProps.$config.minilogo = jsonConfig?.minilogo ?? vueProps.$config.minilogo
|
||||
vueProps.$config.banner = jsonConfig?.banner ?? vueProps.$config.banner
|
||||
|
||||
if (jsonConfig?.error) {
|
||||
vueProps.$config.error[403] = jsonConfig?.error[403] ?? vueProps.$config.error[403]
|
||||
vueProps.$config.error[404] = jsonConfig?.error[404] ?? vueProps.$config.error[404]
|
||||
vueProps.$config.error[500] = jsonConfig?.error[500] ?? vueProps.$config.error[500]
|
||||
}
|
||||
|
||||
if (jsonConfig?.plugins) {
|
||||
jsonConfig.plugins.forEach(plugin => {
|
||||
vueProps.$config.plugins.push(plugin)
|
||||
})
|
||||
}
|
||||
|
||||
vueProps.$config.favicon = jsonConfig?.favicon ?? vueProps.$config.favicon
|
||||
vueProps.$config.css = response?.css ?? null
|
||||
|
||||
await applyStaticCustomization(vueProps.$config.favicon, vueProps.$config.css)
|
||||
}
|
||||
|
||||
async function applyStaticCustomization (favicon, css) {
|
||||
document.getElementById('favicon').href = favicon
|
||||
|
||||
let style = document.getElementById('guiThemeCSS')
|
||||
if (style != null) {
|
||||
style.innerHTML = css
|
||||
} else {
|
||||
style = document.createElement('style')
|
||||
style.setAttribute('id', 'guiThemeCSS')
|
||||
style.innerHTML = css
|
||||
document.body.appendChild(style)
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user