mirror of
https://github.com/databasus/databasus.git
synced 2026-04-06 00:32:03 +02:00
merge develop
This commit is contained in:
@@ -6,14 +6,14 @@ repos:
|
|||||||
hooks:
|
hooks:
|
||||||
- id: frontend-format
|
- id: frontend-format
|
||||||
name: Frontend Format (Prettier)
|
name: Frontend Format (Prettier)
|
||||||
entry: powershell -Command "cd frontend; npm run format"
|
entry: bash -c "cd frontend && npm run format"
|
||||||
language: system
|
language: system
|
||||||
files: ^frontend/.*\.(ts|tsx|js|jsx|json|css|md)$
|
files: ^frontend/.*\.(ts|tsx|js|jsx|json|css|md)$
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
|
|
||||||
- id: frontend-lint
|
- id: frontend-lint
|
||||||
name: Frontend Lint (ESLint)
|
name: Frontend Lint (ESLint)
|
||||||
entry: powershell -Command "cd frontend; npm run lint"
|
entry: bash -c "cd frontend && npm run lint"
|
||||||
language: system
|
language: system
|
||||||
files: ^frontend/.*\.(ts|tsx|js|jsx)$
|
files: ^frontend/.*\.(ts|tsx|js|jsx)$
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
@@ -23,7 +23,7 @@ repos:
|
|||||||
hooks:
|
hooks:
|
||||||
- id: backend-format-and-lint
|
- id: backend-format-and-lint
|
||||||
name: Backend Format & Lint (golangci-lint)
|
name: Backend Format & Lint (golangci-lint)
|
||||||
entry: powershell -Command "cd backend; golangci-lint fmt; golangci-lint run"
|
entry: bash -c "cd backend && golangci-lint run --fix"
|
||||||
language: system
|
language: system
|
||||||
files: ^backend/.*\.go$
|
files: ^backend/.*\.go$
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
|
|||||||
@@ -32,5 +32,5 @@ keywords:
|
|||||||
- mongodb
|
- mongodb
|
||||||
- mariadb
|
- mariadb
|
||||||
license: Apache-2.0
|
license: Apache-2.0
|
||||||
version: 2.18.1
|
version: 2.21.0
|
||||||
date-released: "2025-12-28"
|
date-released: "2026-01-05"
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ echo "Installing PostgreSQL, MySQL, MariaDB and MongoDB client tools for Linux (
|
|||||||
echo
|
echo
|
||||||
|
|
||||||
# Check if running on supported system
|
# Check if running on supported system
|
||||||
if ! command -v apt-get > /dev/null 2>&1; then
|
if ! command -v apt-get &> /dev/null; then
|
||||||
echo "Error: This script requires apt-get (Debian/Ubuntu-like system)"
|
echo "Error: This script requires apt-get (Debian/Ubuntu-like system)"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if running as root or with sudo
|
# Check if running as root or with sudo
|
||||||
if [ $EUID -eq 0 ]; then
|
if [[ $EUID -eq 0 ]]; then
|
||||||
SUDO=""
|
SUDO=""
|
||||||
else
|
else
|
||||||
SUDO="sudo"
|
SUDO="sudo"
|
||||||
@@ -107,12 +107,6 @@ for version in $mysql_versions; do
|
|||||||
version_dir="$MYSQL_DIR/mysql-$version"
|
version_dir="$MYSQL_DIR/mysql-$version"
|
||||||
mkdir -p "$version_dir/bin"
|
mkdir -p "$version_dir/bin"
|
||||||
|
|
||||||
# Skip if already exists
|
|
||||||
if [ -f "$version_dir/bin/mysqldump" ]; then
|
|
||||||
echo " MySQL $version already installed, skipping..."
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Download MySQL client tools from official CDN
|
# Download MySQL client tools from official CDN
|
||||||
# Note: 5.7 is in Downloads, 8.0, 8.4 specific versions are in archives, 9.5 is in MySQL-9.5
|
# Note: 5.7 is in Downloads, 8.0, 8.4 specific versions are in archives, 9.5 is in MySQL-9.5
|
||||||
case $version in
|
case $version in
|
||||||
@@ -138,14 +132,11 @@ for version in $mysql_versions; do
|
|||||||
wget -q "$MYSQL_URL" -O "mysql-$version.tar.gz" || wget -q "$MYSQL_URL" -O "mysql-$version.tar.xz"
|
wget -q "$MYSQL_URL" -O "mysql-$version.tar.gz" || wget -q "$MYSQL_URL" -O "mysql-$version.tar.xz"
|
||||||
|
|
||||||
echo " Extracting MySQL $version..."
|
echo " Extracting MySQL $version..."
|
||||||
case "$MYSQL_URL" in
|
if [[ "$MYSQL_URL" == *.xz ]]; then
|
||||||
*.xz)
|
tar -xJf "mysql-$version.tar.xz" 2>/dev/null || tar -xJf "mysql-$version.tar.gz" 2>/dev/null
|
||||||
tar -xJf "mysql-$version.tar.xz" 2>/dev/null || tar -xJf "mysql-$version.tar.gz" 2>/dev/null
|
else
|
||||||
;;
|
tar -xzf "mysql-$version.tar.gz" 2>/dev/null || tar -xzf "mysql-$version.tar.xz" 2>/dev/null
|
||||||
*)
|
fi
|
||||||
tar -xzf "mysql-$version.tar.gz" 2>/dev/null || tar -xzf "mysql-$version.tar.xz" 2>/dev/null
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Find extracted directory
|
# Find extracted directory
|
||||||
EXTRACTED_DIR=$(ls -d mysql-*/ 2>/dev/null | head -1)
|
EXTRACTED_DIR=$(ls -d mysql-*/ 2>/dev/null | head -1)
|
||||||
@@ -184,7 +175,12 @@ echo "Installing MariaDB client tools to: $MARIADB_DIR"
|
|||||||
# Install dependencies
|
# Install dependencies
|
||||||
$SUDO apt-get install -y -qq apt-transport-https curl
|
$SUDO apt-get install -y -qq apt-transport-https curl
|
||||||
|
|
||||||
# MariaDB versions to install
|
# MariaDB versions to install with their URLs
|
||||||
|
declare -A MARIADB_URLS=(
|
||||||
|
["10.6"]="https://archive.mariadb.org/mariadb-10.6.21/bintar-linux-systemd-x86_64/mariadb-10.6.21-linux-systemd-x86_64.tar.gz"
|
||||||
|
["12.1"]="https://archive.mariadb.org/mariadb-12.1.2/bintar-linux-systemd-x86_64/mariadb-12.1.2-linux-systemd-x86_64.tar.gz"
|
||||||
|
)
|
||||||
|
|
||||||
mariadb_versions="10.6 12.1"
|
mariadb_versions="10.6 12.1"
|
||||||
|
|
||||||
for version in $mariadb_versions; do
|
for version in $mariadb_versions; do
|
||||||
@@ -199,19 +195,7 @@ for version in $mariadb_versions; do
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get URL based on version
|
url=${MARIADB_URLS[$version]}
|
||||||
case "$version" in
|
|
||||||
"10.6")
|
|
||||||
url="https://archive.mariadb.org/mariadb-10.6.21/bintar-linux-systemd-x86_64/mariadb-10.6.21-linux-systemd-x86_64.tar.gz"
|
|
||||||
;;
|
|
||||||
"12.1")
|
|
||||||
url="https://archive.mariadb.org/mariadb-12.1.2/bintar-linux-systemd-x86_64/mariadb-12.1.2-linux-systemd-x86_64.tar.gz"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo " Warning: Unknown MariaDB version $version"
|
|
||||||
continue
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
TEMP_DIR="/tmp/mariadb_install_$version"
|
TEMP_DIR="/tmp/mariadb_install_$version"
|
||||||
mkdir -p "$TEMP_DIR"
|
mkdir -p "$TEMP_DIR"
|
||||||
@@ -254,48 +238,43 @@ mkdir -p "$MONGODB_DIR/bin"
|
|||||||
|
|
||||||
echo "Installing MongoDB Database Tools to: $MONGODB_DIR"
|
echo "Installing MongoDB Database Tools to: $MONGODB_DIR"
|
||||||
|
|
||||||
# Skip if already installed
|
# MongoDB Database Tools are backward compatible - single version supports all servers (4.0-8.0)
|
||||||
if [ -f "$MONGODB_DIR/bin/mongodump" ] && [ -L "$MONGODB_DIR/bin/mongodump" ]; then
|
# Detect architecture
|
||||||
echo "MongoDB Database Tools already installed, skipping..."
|
ARCH=$(uname -m)
|
||||||
|
if [ "$ARCH" = "x86_64" ]; then
|
||||||
|
MONGODB_TOOLS_URL="https://fastdl.mongodb.org/tools/db/mongodb-database-tools-debian12-x86_64-100.10.0.deb"
|
||||||
|
elif [ "$ARCH" = "aarch64" ]; then
|
||||||
|
MONGODB_TOOLS_URL="https://fastdl.mongodb.org/tools/db/mongodb-database-tools-debian12-aarch64-100.10.0.deb"
|
||||||
else
|
else
|
||||||
# MongoDB Database Tools are backward compatible - single version supports all servers (4.0-8.0)
|
echo "Warning: Unsupported architecture $ARCH for MongoDB Database Tools"
|
||||||
# Detect architecture
|
MONGODB_TOOLS_URL=""
|
||||||
ARCH=$(uname -m)
|
fi
|
||||||
if [ "$ARCH" = "x86_64" ]; then
|
|
||||||
MONGODB_TOOLS_URL="https://fastdl.mongodb.org/tools/db/mongodb-database-tools-debian12-x86_64-100.10.0.deb"
|
if [ -n "$MONGODB_TOOLS_URL" ]; then
|
||||||
elif [ "$ARCH" = "aarch64" ]; then
|
TEMP_DIR="/tmp/mongodb_install"
|
||||||
MONGODB_TOOLS_URL="https://fastdl.mongodb.org/tools/db/mongodb-database-tools-debian12-aarch64-100.10.0.deb"
|
mkdir -p "$TEMP_DIR"
|
||||||
else
|
cd "$TEMP_DIR"
|
||||||
echo "Warning: Unsupported architecture $ARCH for MongoDB Database Tools"
|
|
||||||
MONGODB_TOOLS_URL=""
|
echo "Downloading MongoDB Database Tools..."
|
||||||
|
wget -q "$MONGODB_TOOLS_URL" -O mongodb-database-tools.deb || {
|
||||||
|
echo "Warning: Could not download MongoDB Database Tools"
|
||||||
|
cd - >/dev/null
|
||||||
|
rm -rf "$TEMP_DIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -f "mongodb-database-tools.deb" ]; then
|
||||||
|
echo "Installing MongoDB Database Tools..."
|
||||||
|
$SUDO dpkg -i mongodb-database-tools.deb 2>/dev/null || $SUDO apt-get install -f -y -qq
|
||||||
|
|
||||||
|
# Create symlinks to tools directory
|
||||||
|
ln -sf /usr/bin/mongodump "$MONGODB_DIR/bin/mongodump"
|
||||||
|
ln -sf /usr/bin/mongorestore "$MONGODB_DIR/bin/mongorestore"
|
||||||
|
|
||||||
|
echo "MongoDB Database Tools installed successfully"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$MONGODB_TOOLS_URL" ]; then
|
cd - >/dev/null
|
||||||
TEMP_DIR="/tmp/mongodb_install"
|
rm -rf "$TEMP_DIR"
|
||||||
mkdir -p "$TEMP_DIR"
|
|
||||||
cd "$TEMP_DIR"
|
|
||||||
|
|
||||||
echo "Downloading MongoDB Database Tools..."
|
|
||||||
if ! wget -q "$MONGODB_TOOLS_URL" -O mongodb-database-tools.deb; then
|
|
||||||
echo "Warning: Could not download MongoDB Database Tools"
|
|
||||||
cd - >/dev/null
|
|
||||||
rm -rf "$TEMP_DIR"
|
|
||||||
else
|
|
||||||
if [ -f "mongodb-database-tools.deb" ]; then
|
|
||||||
echo "Installing MongoDB Database Tools..."
|
|
||||||
$SUDO dpkg -i mongodb-database-tools.deb 2>/dev/null || $SUDO apt-get install -f -y -qq
|
|
||||||
|
|
||||||
# Create symlinks to tools directory
|
|
||||||
ln -sf /usr/bin/mongodump "$MONGODB_DIR/bin/mongodump"
|
|
||||||
ln -sf /usr/bin/mongorestore "$MONGODB_DIR/bin/mongorestore"
|
|
||||||
|
|
||||||
echo "MongoDB Database Tools installed successfully"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd - >/dev/null
|
|
||||||
rm -rf "$TEMP_DIR"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ export interface GoogleDriveStorage {
|
|||||||
clientId: string;
|
clientId: string;
|
||||||
clientSecret: string;
|
clientSecret: string;
|
||||||
tokenJson?: string;
|
tokenJson?: string;
|
||||||
|
useLocalRedirect?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Button, Input } from 'antd';
|
import { Button, Checkbox, Input } from 'antd';
|
||||||
|
|
||||||
import { GOOGLE_DRIVE_OAUTH_REDIRECT_URL } from '../../../../../constants';
|
import { GOOGLE_DRIVE_OAUTH_REDIRECT_URL } from '../../../../../constants';
|
||||||
import type { Storage } from '../../../../../entity/storages';
|
import type { Storage } from '../../../../../entity/storages';
|
||||||
@@ -16,7 +16,10 @@ export function EditGoogleDriveStorageComponent({ storage, setStorage, setUnsave
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const redirectUri = GOOGLE_DRIVE_OAUTH_REDIRECT_URL;
|
const localRedirectUri = `${window.location.origin}/storages/google-oauth`;
|
||||||
|
const useLocal = storage.googleDriveStorage.useLocalRedirect;
|
||||||
|
const redirectUri = useLocal ? localRedirectUri : GOOGLE_DRIVE_OAUTH_REDIRECT_URL;
|
||||||
|
|
||||||
const clientId = storage.googleDriveStorage.clientId;
|
const clientId = storage.googleDriveStorage.clientId;
|
||||||
const scope = 'https://www.googleapis.com/auth/drive.file';
|
const scope = 'https://www.googleapis.com/auth/drive.file';
|
||||||
const originUrl = `${window.location.origin}/storages/google-oauth`;
|
const originUrl = `${window.location.origin}/storages/google-oauth`;
|
||||||
@@ -92,6 +95,28 @@ export function EditGoogleDriveStorageComponent({ storage, setStorage, setUnsave
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-4 flex w-full flex-col items-start sm:flex-row sm:items-center">
|
||||||
|
<div className="mb-1 min-w-[110px] sm:mb-0" />
|
||||||
|
<Checkbox
|
||||||
|
checked={storage?.googleDriveStorage?.useLocalRedirect || false}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (!storage?.googleDriveStorage) return;
|
||||||
|
|
||||||
|
setStorage({
|
||||||
|
...storage,
|
||||||
|
googleDriveStorage: {
|
||||||
|
...storage.googleDriveStorage,
|
||||||
|
useLocalRedirect: e.target.checked,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
setUnsaved();
|
||||||
|
}}
|
||||||
|
disabled={!!storage?.googleDriveStorage?.tokenJson}
|
||||||
|
>
|
||||||
|
<span className="text-xs">Use local redirect (more secure)</span>
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
{storage?.googleDriveStorage?.tokenJson && (
|
{storage?.googleDriveStorage?.tokenJson && (
|
||||||
<>
|
<>
|
||||||
<div className="mb-1 flex w-full flex-col items-start sm:flex-row sm:items-center">
|
<div className="mb-1 flex w-full flex-col items-start sm:flex-row sm:items-center">
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ export function ShowGoogleDriveStorageComponent({ storage }: Props) {
|
|||||||
{`*************`}
|
{`*************`}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-1 flex items-center">
|
||||||
|
<div className="min-w-[110px]">Use local redirect</div>
|
||||||
|
{`*************`}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="mb-1 flex items-center">
|
<div className="mb-1 flex items-center">
|
||||||
<div className="min-w-[110px]">User Token</div>
|
<div className="min-w-[110px]">User Token</div>
|
||||||
{`*************`}
|
{`*************`}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ export function OauthStorageComponent() {
|
|||||||
const { clientId, clientSecret } = oauthDto.storage.googleDriveStorage;
|
const { clientId, clientSecret } = oauthDto.storage.googleDriveStorage;
|
||||||
const { authCode } = oauthDto;
|
const { authCode } = oauthDto;
|
||||||
|
|
||||||
|
const redirectUri = oauthDto.redirectUrl || GOOGLE_DRIVE_OAUTH_REDIRECT_URL;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Exchange authorization code for access token
|
// Exchange authorization code for access token
|
||||||
const response = await fetch('https://oauth2.googleapis.com/token', {
|
const response = await fetch('https://oauth2.googleapis.com/token', {
|
||||||
@@ -29,13 +31,16 @@ export function OauthStorageComponent() {
|
|||||||
code: authCode,
|
code: authCode,
|
||||||
client_id: clientId,
|
client_id: clientId,
|
||||||
client_secret: clientSecret,
|
client_secret: clientSecret,
|
||||||
redirect_uri: GOOGLE_DRIVE_OAUTH_REDIRECT_URL,
|
redirect_uri: redirectUri,
|
||||||
grant_type: 'authorization_code',
|
grant_type: 'authorization_code',
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`OAuth exchange failed: ${response.statusText}`);
|
const errorData = await response.json();
|
||||||
|
throw new Error(
|
||||||
|
errorData.error_description || `OAuth exchange failed: ${response.statusText}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tokenData = await response.json();
|
const tokenData = await response.json();
|
||||||
@@ -44,27 +49,71 @@ export function OauthStorageComponent() {
|
|||||||
setStorage(oauthDto.storage);
|
setStorage(oauthDto.storage);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert(`Failed to exchange OAuth code: ${error}`);
|
alert(`Failed to exchange OAuth code: ${error}`);
|
||||||
|
// Return to home if exchange fails
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = '/';
|
||||||
|
}, 3000);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
/**
|
||||||
const oauthDtoParam = new URLSearchParams(window.location.search).get('oauthDto');
|
* Helper to validate the DTO and start the exchange process
|
||||||
if (!oauthDtoParam) {
|
*/
|
||||||
alert('OAuth param not found');
|
const processOauthDto = (oauthDto: StorageOauthDto) => {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const decodedParam = decodeURIComponent(oauthDtoParam);
|
|
||||||
const oauthDto: StorageOauthDto = JSON.parse(decodedParam);
|
|
||||||
|
|
||||||
if (oauthDto.storage.type === StorageType.GOOGLE_DRIVE) {
|
if (oauthDto.storage.type === StorageType.GOOGLE_DRIVE) {
|
||||||
if (!oauthDto.storage.googleDriveStorage) {
|
if (!oauthDto.storage.googleDriveStorage) {
|
||||||
alert('Google Drive storage not found');
|
alert('Google Drive storage configuration not found in DTO');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
exchangeGoogleOauthCode(oauthDto);
|
exchangeGoogleOauthCode(oauthDto);
|
||||||
|
} else {
|
||||||
|
alert('Unsupported storage type for OAuth');
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
|
// Attempt 1: Check for the 'oauthDto' param (Third-party/Legacy way)
|
||||||
|
const oauthDtoParam = urlParams.get('oauthDto');
|
||||||
|
if (oauthDtoParam) {
|
||||||
|
try {
|
||||||
|
const decodedParam = decodeURIComponent(oauthDtoParam);
|
||||||
|
const oauthDto: StorageOauthDto = JSON.parse(decodedParam);
|
||||||
|
processOauthDto(oauthDto);
|
||||||
|
return;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error parsing oauthDto parameter:', e);
|
||||||
|
alert('Malformed OAuth parameter received');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt 2: Check for 'code' and 'state' (Direct Google/Local way)
|
||||||
|
const code = urlParams.get('code');
|
||||||
|
const state = urlParams.get('state');
|
||||||
|
|
||||||
|
if (code && state) {
|
||||||
|
try {
|
||||||
|
// The 'state' parameter contains our stringified StorageOauthDto
|
||||||
|
const decodedState = decodeURIComponent(state);
|
||||||
|
const oauthDto: StorageOauthDto = JSON.parse(decodedState);
|
||||||
|
|
||||||
|
// Inject the authorization code received from Google
|
||||||
|
oauthDto.authCode = code;
|
||||||
|
|
||||||
|
processOauthDto(oauthDto);
|
||||||
|
return;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error parsing OAuth state:', e);
|
||||||
|
alert('OAuth state parameter is invalid');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt 3: No valid parameters found
|
||||||
|
alert('OAuth param not found. Ensure the redirect URL is configured correctly.');
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (!storage) {
|
if (!storage) {
|
||||||
|
|||||||
Reference in New Issue
Block a user