Skip to content

Commit

Permalink
feat: magnus 允许 token 多次使用
Browse files Browse the repository at this point in the history
  • Loading branch information
ibuler committed May 9, 2023
1 parent 3a19293 commit b955cf0
Show file tree
Hide file tree
Showing 11 changed files with 98 additions and 23 deletions.
10 changes: 9 additions & 1 deletion src/app/elements/connect/acl-dialog/acl-dialog.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ <h2 mat-dialog-title> {{ 'Login reminder' | translate }} </h2>
<button mat-raised-button (click)="closeDialog()">{{ "Close" | translate }}</button>
</mat-dialog-actions>
</div>
</div>

<div *ngSwitchDefault>
<mat-dialog-content>
<div class="error-message">{{ JSON.stringify(data.error.error) }}</div>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-raised-button (click)="closeDialog()">{{ "Close" | translate }}</button>
</mat-dialog-actions>
</div>
</div>
</div>
4 changes: 4 additions & 0 deletions src/app/elements/connect/acl-dialog/acl-dialog.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {Asset, ConnectData, ConnectionToken} from '@app/model';
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material';
import {HttpService, I18nService} from '@app/services';
import {ToastrService} from 'ngx-toastr';
import {HttpErrorResponse} from '@angular/common/http';

@Component({
selector: 'elements-acl-dialog',
Expand All @@ -14,6 +15,7 @@ export class ElementACLDialogComponent implements OnInit {
public connectInfo: ConnectData;
public code: string;
public connectionToken: ConnectionToken = null;
public error: HttpErrorResponse;
public otherError: string;
public ticketAssignees: string = '-';
// Token 的行为,创建或者兑换 Token, create, exchange
Expand Down Expand Up @@ -121,4 +123,6 @@ export class ElementACLDialogComponent implements OnInit {
);
}, 3000);
}

protected readonly JSON = JSON;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ <h2 class="subject">{{ 'Database connect info' | translate }}</h2>
<td class="title">{{ item.label | async }} </td>
<td class="text-td"
#tooltip="matTooltip"
[matTooltip]="'Click to copy' | translate"
[matTooltip]="hoverTip"
matTooltipPosition="right"
ngxClipboard
(cbOnSuccess)="onCopySuccess($event)"
(mouseenter)="onHover($event)"
[cbContent]="this.info[item.name]"
>
<span *ngIf="item.name === 'password'" (click)="showPassword($event)" class="show-password">
Expand All @@ -18,9 +19,17 @@ <h2 class="subject">{{ 'Database connect info' | translate }}</h2>
</span>
<i class="fa fa-eye"></i>
</span>
<span *ngIf="item.name !== 'password'">
<span *ngIf="item.name !== 'password' && item.name !== 'set_reusable'">
{{ this.info[item.name] }}
</span>
<span *ngIf="item.name == 'set_reusable'" class="reusable-button">
<mat-slide-toggle
[(ngModel)]="token.is_reusable"
(change)="setReusable($event)"
>
{{ "Re-use for a long time after opening" | translate }}
</mat-slide-toggle>
</span>
<span class="btn">
<i class="fa fa-clone icon"></i>
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,15 @@ iframe {
width: 15px;
height: 15px;
}

.reusable-button ::ng-deep {
.mat-slide-toggle-bar {
background-color: gray;
}
.mat-slide-toggle.mat-checked .mat-slide-toggle-bar {
background-color: var(--primary-color) !important;
}
.mat-slide-toggle.mat-checked:not(.mat-disabled) .mat-slide-toggle-thumb {
background-color: white;
}
}
44 changes: 34 additions & 10 deletions src/app/elements/content/content-window/magnus/magnus.component.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {Component, Input, OnInit} from '@angular/core';
import {Component, Input, OnInit, ViewChild} from '@angular/core';
import {View, Account, Endpoint, Asset, ConnectionToken} from '@app/model';
import {ConnectTokenService, HttpService, I18nService, SettingService} from '@app/services';
import {User} from '@app/globals';
import {ToastrService} from 'ngx-toastr';
import {MatTooltip} from '@angular/material/tooltip';

interface InfoItem {
name: string;
Expand All @@ -18,6 +19,7 @@ interface InfoItem {

export class ElementConnectorMagnusComponent implements OnInit {
@Input() view: View;
@ViewChild(MatTooltip, {static: false}) tooltip: MatTooltip;

asset: Asset;
account: Account;
Expand All @@ -34,6 +36,8 @@ export class ElementConnectorMagnusComponent implements OnInit {
passwordMask = '******';
passwordShow = '******';
token: ConnectionToken;
showSetReusable: boolean;
hoverTip: string = this._i18n.instant('Click to copy');

constructor(private _http: HttpService,
private _i18n: I18nService,
Expand All @@ -42,6 +46,7 @@ export class ElementConnectorMagnusComponent implements OnInit {
private _settingSvc: SettingService
) {
this.globalSetting = this._settingSvc.globalSetting;
this.showSetReusable = this.globalSetting.CONNECTION_TOKEN_REUSABLE;
}

async ngOnInit() {
Expand All @@ -57,7 +62,7 @@ export class ElementConnectorMagnusComponent implements OnInit {
this.setDBInfo();
this.generateConnCli();
this.loading = false;
this.view.termComp = this
this.view.termComp = this;
}

setDBInfo() {
Expand All @@ -72,8 +77,11 @@ export class ElementConnectorMagnusComponent implements OnInit {
{name: 'password', value: this.token.value, label: this._i18n.t('Password')},
{name: 'database', value: database, label: this._i18n.t('Database')},
{name: 'protocol', value: this.protocol, label: this._i18n.t('Protocol')},
{name: 'expire_time', value: `${this.token.expire_time} s` , label: this._i18n.t('Expire time')},
{name: 'date_expired', value: `${this.token.date_expired}` , label: this._i18n.t('Expire time')},
];
if (this.showSetReusable) {
this.infoItems.push({name: 'set_reusable', value: '', label: this._i18n.t('Set reusable')});
}
this.info = this.infoItems.reduce((pre, current) => {
pre[current.name] = current.value;
return pre;
Expand Down Expand Up @@ -126,6 +134,19 @@ export class ElementConnectorMagnusComponent implements OnInit {
this.cli = cli.replace(passwordHolder, password);
}

setReusable(event) {
this._connectTokenSvc.setReusable(this.token, event.checked).subscribe(
res => {
this.token = Object.assign(this.token, res);
this.info['date_expired'] = `${this.token.date_expired}`;
},
error => {
this.token.is_reusable = false;
this._toastr.error(error.error.msg || error.error.is_reusable || error.message );
}
);
}

startClient() {
const {protocol} = this.info;
const data = {
Expand All @@ -149,19 +170,22 @@ export class ElementConnectorMagnusComponent implements OnInit {
}

async onCopySuccess(evt) {
const msg = await this._i18n.t('Copied');
this._toastr.success(msg);
this.hoverTip = this._i18n.instant('Copied');
}

onHover(evt) {
this.hoverTip = this._i18n.instant('Click to copy');
}

async reconnect() {
const oldConnectToken = this.view.connectToken
const newConnectToken = await this._connectTokenSvc.exchange(oldConnectToken)
const oldConnectToken = this.view.connectToken;
const newConnectToken = await this._connectTokenSvc.exchange(oldConnectToken);
if (!newConnectToken) {
return
return;
}
// 更新当前 view 的 connectToken
this.view.connectToken = newConnectToken
await this.ngOnInit()
this.view.connectToken = newConnectToken;
await this.ngOnInit();
// 刷新完成隐藏密码
this.passwordShow = this.passwordMask;
}
Expand Down
3 changes: 3 additions & 0 deletions src/app/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ export class GlobalSetting {
INTERFACE: any;
TERMINAL_OMNIDB_ENABLED: boolean;
TERMINAL_GRAPHICAL_RESOLUTION: string;
CONNECTION_TOKEN_REUSABLE: boolean;
}

export class Setting {
Expand Down Expand Up @@ -389,6 +390,8 @@ export class ConnectionToken {
account: string;
expire_time: number;
is_active: boolean;
date_expired: Date;
is_reusable: boolean;
from_ticket: {
id: string;
};
Expand Down
13 changes: 10 additions & 3 deletions src/app/services/connect-token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ export class ConnectTokenService {
create(asset: Asset, connectInfo: ConnectData): Promise<ConnectionToken> {
return new Promise<ConnectionToken>((resolve, reject) => {
this._http.createConnectToken(asset, connectInfo).subscribe(
(token: ConnectionToken) => {resolve(token);},
(token: ConnectionToken) => { resolve(token); },
(error) => {
this.handleError({asset, connectInfo, code: error.error.code, tokenAction: 'create'}, resolve)
console.log('Error: ', error);
this.handleError({asset, connectInfo, code: error.error.code, tokenAction: 'create', error: error}, resolve );
}
);
});
Expand All @@ -38,9 +39,15 @@ export class ConnectTokenService {
this._http.exchangeConnectToken(connectToken.id).subscribe(
(token: ConnectionToken) => { resolve(token); },
(error) => {
this.handleError({tokenID: connectToken.id, code: error.error.code, tokenAction: 'exchange'}, resolve)
this.handleError({tokenID: connectToken.id, code: error.error.code, tokenAction: 'exchange'}, resolve);
}
);
});
}

setReusable(connectToken: ConnectionToken, reusable: Boolean) {
const url = `/api/v1/authentication/connection-token/${connectToken.id}/`;
const data = {is_reusable: reusable};
return this._http.patch(url, data);
}
}
14 changes: 8 additions & 6 deletions src/app/services/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ export class HttpService {
);
}

patch<T>(url: string, options?: any): Observable<any> {
patch<T>(url: string, body?: any, options?: any): Observable<any> {
options = this.setOptionsCSRFToken(options);
return this.http.patch(url, options).pipe(
return this.http.patch(url, body, options).pipe(
catchError(this.handleError.bind(this))
);
}
Expand Down Expand Up @@ -282,11 +282,13 @@ export class HttpService {
}

async handleConnectMethodExpiredError(error) {
if (error.status === 400 && error.error && error.error.error && error.error.error.startsWith('Connect method')) {
const errMsg = await this._i18n.t('The connection method is invalid, please refresh the page')
alert(errMsg)
if (error.status === 400 ) {
if (error.error && error.error.error && error.error.error.startsWith('Connect method')) {
const errMsg = await this._i18n.t('The connection method is invalid, please refresh the page');
alert(errMsg);
}
}
throw error
throw error;
}

getSmartEndpoint({ assetId, sessionId, token }, protocol ): Promise<Endpoint> {
Expand Down
2 changes: 2 additions & 0 deletions src/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,5 +143,7 @@
"Copy link": "Copy link",
"Login review approved": "Login review has been approved, connecting assets...",
"No account available": "No available accounts",
"Set reusable": "Set reusable",
"Re-use for a long time after opening": "Re-use for a long time after opening",
"The connection method is invalid, please refresh the page": "The connection method is invalid, please refresh the page"
}
2 changes: 2 additions & 0 deletions src/assets/i18n/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,5 +146,7 @@
"Copy link": "リンクをコピーする",
"Login review approved": "ログイン監査に合格し、アセットを接続しています...",
"No account available": "アカウントがありません",
"Set reusable": "再利用可能な",
"Re-use for a long time after opening": "開いた後、長い間再利用する",
"The connection method is invalid, please refresh the page": "接続方法が無効です。ページを更新してください"
}
4 changes: 3 additions & 1 deletion src/assets/i18n/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
"General": "基本配置",
"Applet connect method": "远程应用连接方式",
"Client": "客户端",

"Keyboard layout": "键盘布局",
"UK English keyboard layout": "UK English (Qwerty)",
"US English keyboard layout": "US English (Qwerty)",
Expand All @@ -146,6 +146,8 @@
"Copy link": "复制链接",
"Login review approved": "登录审核已通过, 正在连接资产...",
"No account available": "没有可用账号",
"Set reusable": "开启复用",
"Re-use for a long time after opening": "开启后该连接信息可长时间多次使用",
"The connection method is invalid, please refresh the page": "该连接方式已失效,请刷新页面"
}

0 comments on commit b955cf0

Please sign in to comment.