Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

6 database tools #12

Merged
merged 25 commits into from
Nov 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
"request": "launch",
"preLaunchTask": "npm: test",
"url": "http://localhost:9876/debug.html"
},
{
"name": "proxy",
"type": "debugpy",
"request": "launch",
"preLaunchTask": "",
"program": "CodeChefDatabaseProxy/proxy.py"
}
]
}
153 changes: 153 additions & 0 deletions CodeChefDatabaseProxy/proxy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import pyodbc
import uuid
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
import uvicorn
from colorama import Fore, Style, init

# Initialize colorama
init(autoreset=True)

from fastapi.middleware.cors import CORSMiddleware

# Initialize FastAPI app
app = FastAPI()

origins = [
"https://codechef.ipdotsetaf.ir",
"https://ipdotsetaf.github.ir",
"http://localhost:4200"
]

app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

# In-memory dictionary to store database connections
connections = {}
connection_index_counter = 1

# Request models
class ConnectRequest(BaseModel):
server: str
username: str
password: str

class QueryRequest(BaseModel):
connection_id: str
catalog: str = None
query: str

class DisconnectRequest(BaseModel):
connection_id: str

# Function to log connection attempts
def log_connect(index, username, server, connection_id=None, success=True):
index_text = f"{Fore.YELLOW}[{index}]{Style.RESET_ALL}" if index is not None else ""
endpoint_text = f"{Fore.GREEN}connect{Style.RESET_ALL}"
if success:
print(f"{index_text} {endpoint_text}: {username}@{server}, Connection ID: {connection_id}")
else:
print(f"{endpoint_text}: Failed to connect - {username}@{server}")

# Function to log disconnections
def log_disconnect(index, username, server, connection_id):
index_text = f"{Fore.YELLOW}[{index}]{Style.RESET_ALL}"
endpoint_text = f"{Fore.GREEN}disconnect{Style.RESET_ALL}"
print(f"{index_text} {endpoint_text}: {username}@{server}, Connection ID: {connection_id}")

# Function to log executed queries
def log_query(index, query):
index_text = f"{Fore.YELLOW}[{index}]{Style.RESET_ALL}"
endpoint_text = f"{Fore.GREEN}execute-query{Style.RESET_ALL}"
print(f"{index_text} {endpoint_text}: Executed query: {query}")

# Establish a database connection and return a unique connection ID
@app.post("/connect")
async def connect(request: ConnectRequest):
global connection_index_counter
connection_string = f"Driver={{SQL Server}};Server={request.server};UID={request.username};PWD={request.password};"
try:
# Attempt to connect to the database
connection = pyodbc.connect(connection_string, timeout=5)

# Generate a unique ID and index for the connection
connection_id = str(uuid.uuid4())
index = connection_index_counter
connection_index_counter += 1

# Store connection details in the dictionary
connections[connection_id] = {
"connection": connection,
"index": index,
"username": request.username,
"server": request.server
}

# Log successful connection
log_connect(index, request.username, request.server, connection_id)

return {"status": "connected", "connection_id": connection_id}
except Exception as e:
# Log failed connection attempt
log_connect(None, request.username, request.server, success=False)
raise HTTPException(status_code=500, detail=f"Failed to connect to database: {e}")

# Execute a SQL query using the specified connection ID
@app.post("/execute-query")
async def execute_query(request: QueryRequest):
connection_data = connections.get(request.connection_id)
if not connection_data:
raise HTTPException(status_code=404, detail="Connection ID not found")

connection = connection_data["connection"]
index = connection_data["index"]

try:
# Execute the query and fetch results
cursor = connection.cursor()
if(request.catalog):
cursor.execute(f"USE {request.catalog}")
cursor.commit()
cursor.execute(request.query)
columns = [column[0] for column in cursor.description]
rows = [dict(zip(columns, row)) for row in cursor.fetchall()]

# Log executed query
log_query(index, request.query)

return {"status": "success", "data": rows}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))

# Disconnect from the database using the specified connection ID
@app.post("/disconnect")
async def disconnect(request: DisconnectRequest):
connection_data = connections.pop(request.connection_id, None)
if not connection_data:
raise HTTPException(status_code=404, detail="Connection ID not found")

connection = connection_data["connection"]
index = connection_data["index"]
username = connection_data["username"]
server = connection_data["server"]

try:
# Close the connection
connection.close()

# Log disconnection
log_disconnect(index, username, server, request.connection_id)

return {"status": "disconnected", "connection_id": request.connection_id}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Failed to disconnect: {e}")

# Run the FastAPI server
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=50505, access_log=False)
4 changes: 4 additions & 0 deletions CodeChefDatabaseProxy/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fastapi==0.115.4
uvicorn==0.32.0
pyodbc==5.2.0
colorama==0.4.6
4 changes: 3 additions & 1 deletion src/app/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { provideClientHydration } from '@angular/platform-browser';
import { provideAnimations } from '@angular/platform-browser/animations';
import { provideHttpClient, withFetch } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes),
provideClientHydration(),
provideAnimations()
provideAnimations(),
provideHttpClient(withFetch())
]
};
6 changes: 5 additions & 1 deletion src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ import { Cs2tsComponent } from './cs2ts/cs2ts.component';
import { HomeComponent } from './home/home.component';
import { Md2htmlComponent } from './md2html/md2html.component';
import { SerializedToolComponent } from './serialized-tool/serialized-tool.component';
import { MssqlScaffolderComponent } from './mssql-scaffolder/mssql-scaffolder.component';
import { DownloadsComponent } from './downloads/downloads.component';

export const routes: Routes = [
{ path: '', title: "CodeChef", component: HomeComponent },
{ path: '', title: "CodeChef", component: HomeComponent, data: { header: false } },
{ path: 'cs2ts', title: "C# to TS • CodeChef", component: Cs2tsComponent },
{ path: 'md2html', title: "MD to HTML • CodeChef", component: Md2htmlComponent },
{ path: 'serialized', title: "Serialized Tool • CodeChef", component: SerializedToolComponent },
{ path: 'mssqlscaffold', title: "MSSQL Scaffolder • CodeChef", component: MssqlScaffolderComponent },
{ path: 'downloads', title: "Downloads • CodeChef", component: DownloadsComponent },

{ path: '**', title: "Not Found • CodeChef", component: NotFoundComponent },
];
6 changes: 4 additions & 2 deletions src/app/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<app-header/>
@if (header) {
<app-header />
}
<router-outlet />
<app-footer/>
<app-footer />
31 changes: 28 additions & 3 deletions src/app/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { Component, Inject, PLATFORM_ID } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router, RouterOutlet } from '@angular/router';
import { HeaderComponent } from "../header/header.component";
import { FooterComponent } from "../footer/footer.component";
import packageJson from '../../../package.json';
import { Meta } from '@angular/platform-browser';
import { isPlatformBrowser } from '@angular/common';
import { filter, map, mergeMap } from 'rxjs';

@Component({
selector: 'app-root',
Expand All @@ -13,8 +15,31 @@ import { Meta } from '@angular/platform-browser';
})
export class AppComponent {
public static version: string = packageJson.version;
public static isBrowser = false;
protected header: boolean = true;

constructor(meta: Meta) {
constructor(
@Inject(PLATFORM_ID) private platformId: any,
meta: Meta,
private activatedRoute: ActivatedRoute,
private router: Router
) {
AppComponent.isBrowser = isPlatformBrowser(this.platformId);
meta.addTag({ name: "author", content: "IPdotSetAF" });

this.router.events.pipe(
filter(e => e instanceof NavigationEnd),
map(() => activatedRoute),
map(route => {
while (route.firstChild) {
route = route.firstChild;
}
return route;
}),
mergeMap(route => route.data),
map(data => {
this.header = data['header'] ?? true;
})
).subscribe();
}
}
1 change: 1 addition & 0 deletions src/app/cs2ts/cs2ts.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export class Cs2tsComponent implements AfterContentInit {
return "bigint";
case "char":
case "string":
case "guid":
return "string";
case "datetime":
case "dateonly":
Expand Down
20 changes: 20 additions & 0 deletions src/app/downloads/downloads.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<div class="container vh-100 p-4">
<div class="col-12">
<h1 class="bi bi-download"> Downloads</h1>
<p>Here You can download required or useful softwares.</p>

<h2 class="bi bi-database"> MSSQl proxy server</h2>
<p>This proxy server is neccessary for any codechef tool that needs to communicate with MSSQL server. this
server will expose http endpoints for connecting, disconnecting and executing queries against the connected
database. this proxy can connect to multiple databases at the same time.
</p>
<p>Choose proper version based on your operating system.</p>
<div class="row">
<div class="d-flex justify-content-center gap-2">
<a class="bi bi-windows btn btn-success"> Windows</a>
<a class="bi bi-ubuntu btn btn-success"> Linux</a>
<a class="bi bi-apple btn btn-success"> MacOS</a>
</div>
</div>
</div>
</div>
23 changes: 23 additions & 0 deletions src/app/downloads/downloads.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { DownloadsComponent } from './downloads.component';

describe('DownloadsComponent', () => {
let component: DownloadsComponent;
let fixture: ComponentFixture<DownloadsComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [DownloadsComponent]
})
.compileComponents();

fixture = TestBed.createComponent(DownloadsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
11 changes: 11 additions & 0 deletions src/app/downloads/downloads.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Component } from '@angular/core';

@Component({
selector: 'app-downloads',
standalone: true,
imports: [],
templateUrl: './downloads.component.html'
})
export class DownloadsComponent {

}
10 changes: 1 addition & 9 deletions src/app/footer/footer.component.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,4 @@ a {
#logo {
filter: brightness(0%) invert() brightness(40%);
height: 20px;
}

.fs-md{
font-size: smaller;
}

.fs-sm{
font-size: small;
}
}
6 changes: 4 additions & 2 deletions src/app/footer/footer.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ <h3 class="fs-6 m-0">CodeChef v{{version}}</h3>
GPL-3.0
License.</label>
</div>
<div class="col-md-6 d-flex justify-content-center justify-content-md-end gap-2">
<a class="btn-footer btn-circle btn-hover bi bi-telephone fs-5" title="Call Me"
<div class="col-md-6 d-flex flex-wrap justify-content-center justify-content-md-end gap-2">
<a class="btn-footer btn-circle btn-hover bi bi-telephone fs-5" title="Call"
href="tel:+989387016860"></a>
<a class="btn-footer btn-circle btn-hover bi bi-envelope-at fs-5" title="Email"
href="mailto:[email protected]"></a>
<a class="btn-footer btn-circle btn-hover bi bi-globe2 fs-5" title="Website"
href="https://ipdotsetaf.ir"></a>
<a class="btn-footer btn-circle btn-hover bi bi-telegram fs-5" title="Telegram"
Expand Down
Loading
Loading