Compare commits

...
6 Commits
Author SHA1 Message Date
serge-rider e54e8ddb66 dbeaver/pro#2176 Localhost IP resolve fix 2023-12-08 13:36:10 +03:00
serge-rider 6560fff886 Merge branch 'release_23_3_0' of https://github.com/dbeaver/cloudbeaver into release_23_3_0 2023-12-08 07:51:54 +03:00
serge-rider b01b939cf7 dbeaver/pro#2176 Localhost domain name resolve fix 2023-12-08 07:51:47 +03:00
Ainurandnaumov 2c627132c0 CB-4314 add test locale (#2210)
Co-authored-by: naumov <iamemptyhuh@gmail.com>
2023-12-07 14:26:30 +03:00
AlexeyandDaria Marutkina 1e77a8fc86 CB-4317 fix: require authentication to load connection origin details (#2189)
* CB-4317 fix: require authentication to load connection origin details

* CB-4317 fix: ensure user loaded and up to date

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-12-06 20:36:39 +03:00
Ainur e38a7a94e2 CB-4328 hotfix json values update (#2201)
* CB-4328 get updated rows info only using key identifier attributes

* CB-4328 do not refresh row for nosql db
2023-12-05 19:57:31 +03:00
10 changed files with 94 additions and 40 deletions
@@ -22,9 +22,7 @@ import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.data.DBDAttributeBinding;
import org.jkiss.dbeaver.model.data.DBDRowIdentifier;
import org.jkiss.dbeaver.model.struct.DBSAttributeBase;
import org.jkiss.dbeaver.model.struct.DBSDataContainer;
import org.jkiss.dbeaver.model.struct.DBSTypedObject;
import org.jkiss.dbeaver.model.struct.*;
import java.util.HashSet;
import java.util.List;
@@ -126,4 +124,12 @@ public class WebSQLResultsInfo {
return null;
}
public boolean canRefreshResults() {
DBSEntity entity = getDefaultRowIdentifier().getEntity();
// FIXME: do not refresh documents for now. Can be solved by extracting document ID attributes
// FIXME: but it will require to provide dynamic document metadata.
return entity == null || entity.getDataSource() == null ||
(!(entity instanceof DBSDocumentContainer) && !entity.getDataSource().getInfo().isDynamicMetadata());
}
}
@@ -557,7 +557,12 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
} else if (serverURL == null) {
String hostName = serverHost;
if (CommonUtils.isEmpty(hostName)) {
hostName = InetAddress.getLocalHost().getHostName();
try {
hostName = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
log.debug("Error resolving localhost address: " + e.getMessage());
hostName = "localhost";
}
}
serverURL = "http://" + hostName + ":" + serverPort;
}
@@ -604,7 +609,7 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
}
}
parseAdditionalConfiguration(configProps);
} catch (IOException | DBException e) {
} catch (DBException e) {
throw new DBException("Error parsing server configuration", e);
}
@@ -58,6 +58,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
* Web SQL processor.
@@ -417,13 +418,22 @@ public class WebSQLProcessor implements WebSessionProvider {
DBCExecutionPurpose.UTIL,
"Refresh row(s) after insert/update")
) {
boolean canRefreshResults = resultsInfo.canRefreshResults();
for (Object[] row : newResultSetRows) {
if (row.length == 0) {
continue;
}
if (!canRefreshResults) {
makeWebCellRow(resultsInfo, row, dataFormat);
continue;
}
List<DBDAttributeConstraint> constraints = new ArrayList<>();
boolean hasKey = true;
for (DBDAttributeBinding attr : resultsInfo.getAttributes()) {
// get attributes only from row identifiers
Set<DBDAttributeBinding> idAttributes = resultsInfo.getRowIdentifiers().stream()
.flatMap(r -> r.getAttributes().stream())
.collect(Collectors.toSet());
for (DBDAttributeBinding attr : idAttributes) {
if (attr.getRowIdentifier() == null) {
continue;
}
@@ -439,6 +449,7 @@ public class WebSQLProcessor implements WebSessionProvider {
}
if (!hasKey) {
// No key value for this row
makeWebCellRow(resultsInfo, row, dataFormat);
continue;
}
DBDDataFilter filter = new DBDDataFilter(constraints);
@@ -457,6 +468,20 @@ public class WebSQLProcessor implements WebSessionProvider {
}
}
private void makeWebCellRow(
@NotNull WebSQLResultsInfo resultsInfo,
@NotNull Object[] row,
@Nullable WebDataFormat dataFormat
) throws DBCException {
for (int i = 0; i < row.length; i++) {
row[i] = WebSQLUtils.makeWebCellValue(
webSession,
resultsInfo.getAttributeByPosition(i),
row[i],
dataFormat);
}
}
public String generateResultsDataUpdateScript(
@NotNull DBRProgressMonitor monitor,
@NotNull WebSQLContextInfo contextInfo,
@@ -57,6 +57,7 @@ import org.jkiss.utils.SecurityUtils;
import java.io.*;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.util.*;
@@ -458,8 +459,12 @@ public class CBDatabase {
}
private void checkInstanceRecord(Connection connection) throws SQLException, IOException {
InetAddress localHost = InetAddress.getLocalHost();
String hostName = localHost.getHostName();
String hostName;
try {
hostName = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
hostName = "localhost";
}
byte[] hardwareAddress = RuntimeUtils.getLocalMacAddress();
String macAddress = CommonUtils.toHexString(hardwareAddress);
@@ -107,6 +107,7 @@ export default [
['ui_upload_file_fail', 'Failed to upload file'],
['ui_filter', 'Filter'],
['ui_disable', 'Disable'],
['ui_test', 'Test'],
['root_permission_denied', "You don't have permissions"],
['root_permission_no_permission', "You don't have permission for this action"],
@@ -91,6 +91,7 @@ export default [
['ui_upload_file_fail', 'Failed to upload file'],
['ui_filter', 'Filter'],
['ui_disable', 'Disable'],
['ui_test', 'Test'],
['root_permission_denied', 'Non hai i permessi'],
['app_root_session_expire_warning_title', 'La sessione sta per scadere'],
@@ -103,6 +103,7 @@ export default [
['ui_upload_file_fail', 'Не удалось загрузить файл'],
['ui_filter', 'Фильтр'],
['ui_disable', 'Отключить'],
['ui_test', 'Проверить'],
['root_permission_denied', 'Отказано в доступе'],
['root_permission_no_permission', 'У вас нет разрешения на это действие'],
@@ -104,6 +104,7 @@ export default [
['ui_upload_file_fail', 'Failed to upload file'],
['ui_filter', 'Filter'],
['ui_disable', 'Disable'],
['ui_test', 'Test'],
['root_permission_denied', '您没有权限'],
['root_permission_no_permission', '您没有权限执行此操作'],
@@ -6,19 +6,11 @@
* you may not use this file except in compliance with the License.
*/
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { Button, Container, GroupItem, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
import { Button, Container, useTranslate } from '@cloudbeaver/core-blocks';
import { useAuthenticationAction } from './useAuthenticationAction';
const styles = css`
Container {
justify-content: center;
align-items: center;
}
`;
export type Props = {
providerId: string;
className?: string;
@@ -29,21 +21,22 @@ export type Props = {
export const AuthenticationProvider = observer<Props>(function AuthenticationProvider(props) {
const translate = useTranslate();
const style = useStyles(styles);
const action = useAuthenticationAction(props);
if (action.authorized) {
return (props.children?.() as null) || null;
}
return styled(style)(
<Container className={props.className} gap vertical>
<GroupItem keepSize>{translate('authentication_request_token')}</GroupItem>
<GroupItem keepSize>
<Button type="button" mod={['unelevated']} loading={action.authenticating} onClick={action.auth}>
{translate('authentication_authenticate')}
</Button>
</GroupItem>
</Container>,
return (
<Container className={props.className} gap vertical center>
<Container keepSize center vertical gap dense>
<Container keepSize>{translate('authentication_request_token')}</Container>
<Container keepSize>
<Button type="button" mod={['unelevated']} loading={action.authenticating} onClick={action.auth}>
{translate('authentication_authenticate')}
</Button>
</Container>
</Container>
</Container>
);
});
@@ -9,6 +9,7 @@ import { runInAction } from 'mobx';
import { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import { AUTH_PROVIDER_LOCAL_ID, AuthProvidersResource, UserInfoResource } from '@cloudbeaver/core-authentication';
import {
ColoredContainer,
ExceptionMessage,
@@ -20,7 +21,7 @@ import {
useStyles,
useTranslate,
} from '@cloudbeaver/core-blocks';
import { createConnectionParam } from '@cloudbeaver/core-connections';
import { createConnectionParam, DatabaseAuthModelsResource, DBDriverResource } from '@cloudbeaver/core-connections';
import { TabContainerPanelComponent, useTab, useTabState } from '@cloudbeaver/core-ui';
import type { IConnectionFormProps } from '../IConnectionFormProps';
@@ -38,12 +39,25 @@ const style = css`
}
`;
export const OriginInfo: TabContainerPanelComponent<IConnectionFormProps> = observer(function OriginInfo({ tabId, state: { info, resource } }) {
export const OriginInfo: TabContainerPanelComponent<IConnectionFormProps> = observer(function OriginInfo({
tabId,
state: { info, resource, config },
}) {
const tab = useTab(tabId);
const translate = useTranslate();
// const userInfoService = useService(UserInfoResource);
const userInfoLoader = useResource(OriginInfo, UserInfoResource, undefined);
const state = useTabState<Record<string, any>>();
const styles = useStyles(style);
const driverLoader = useResource(OriginInfo, DBDriverResource, config.driverId ?? null);
const authModeLoader = useResource(
OriginInfo,
DatabaseAuthModelsResource,
config.authModelId ?? info?.authModel ?? driverLoader.data?.defaultAuthModel ?? null,
);
const providerId = authModeLoader.data?.requiredAuth ?? info?.requiredAuth ?? AUTH_PROVIDER_LOCAL_ID;
const isAuthenticated = userInfoLoader.resource.hasToken(providerId);
const providerLoader = useResource(OriginInfo, AuthProvidersResource, providerId);
const connection = useResource(
OriginInfo,
@@ -53,7 +67,7 @@ export const OriginInfo: TabContainerPanelComponent<IConnectionFormProps> = obse
includes: ['includeOrigin', 'customIncludeOriginDetails'] as const,
},
{
// isActive: () => !info?.origin || userInfoService.hasOrigin(info.origin),
active: isAuthenticated,
onData: connection => {
runInAction(() => {
if (!connection.origin.details) {
@@ -89,15 +103,17 @@ export const OriginInfo: TabContainerPanelComponent<IConnectionFormProps> = obse
);
}
// const authorized = !info?.origin || userInfoService.hasOrigin(info.origin);
// if (!authorized && info?.origin) {
// return styled(styles)(
// <ColoredContainer parent vertical>
// <AuthenticationProvider origin={info.origin} onAuthenticate={connection.reload} />
// </ColoredContainer>
// );
// }
if (!isAuthenticated) {
return styled(styles)(
<ColoredContainer parent>
<TextPlaceholder>
{translate('connections_public_connection_cloud_auth_required', undefined, {
providerLabel: providerLoader.data?.label,
})}
</TextPlaceholder>
</ColoredContainer>,
);
}
if (!connection.data?.origin.details || connection.data.origin.details.length === 0) {
return styled(styles)(