Skip to content

Commit

Permalink
feat(gui): server-side pagination
Browse files Browse the repository at this point in the history
  • Loading branch information
rgmz authored and Richard Gomez committed Jun 29, 2024
1 parent 7dcb4ab commit 1732732
Show file tree
Hide file tree
Showing 13 changed files with 280 additions and 96 deletions.
41 changes: 22 additions & 19 deletions roadlib/roadtools/roadlib/metadef/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,10 @@ def __repr__(self):
Column('Device', Text, ForeignKey('Devices.objectId'))
)

class AppRoleAssignment(Base, SerializeMixin):
class ModelBase(Base, SerializeMixin):
__abstract__ = True

class AppRoleAssignment(ModelBase):
__tablename__ = "AppRoleAssignments"
objectType = Column(Text)
objectId = Column(Text, primary_key=True)
Expand All @@ -171,7 +174,7 @@ class AppRoleAssignment(Base, SerializeMixin):
resourceId = Column(Text)


class OAuth2PermissionGrant(Base, SerializeMixin):
class OAuth2PermissionGrant(ModelBase):
__tablename__ = "OAuth2PermissionGrants"
clientId = Column(Text)
consentType = Column(Text)
Expand All @@ -183,7 +186,7 @@ class OAuth2PermissionGrant(Base, SerializeMixin):
startTime = Column(DateTime)


class User(Base, SerializeMixin):
class User(ModelBase):
__tablename__ = "Users"
objectType = Column(Text)
objectId = Column(Text, primary_key=True)
Expand Down Expand Up @@ -335,7 +338,7 @@ class User(Base, SerializeMixin):
back_populates="memberUsers")


class ServicePrincipal(Base, SerializeMixin):
class ServicePrincipal(ModelBase):
__tablename__ = "ServicePrincipals"
objectType = Column(Text)
objectId = Column(Text, primary_key=True)
Expand Down Expand Up @@ -422,7 +425,7 @@ class ServicePrincipal(Base, SerializeMixin):
primaryjoin=objectId == foreign(AppRoleAssignment.principalId))


class Group(Base, SerializeMixin):
class Group(ModelBase):
__tablename__ = "Groups"
objectType = Column(Text)
objectId = Column(Text, primary_key=True)
Expand Down Expand Up @@ -514,7 +517,7 @@ class Group(Base, SerializeMixin):
back_populates="memberGroups")


class Application(Base, SerializeMixin):
class Application(ModelBase):
__tablename__ = "Applications"
objectType = Column(Text)
objectId = Column(Text, primary_key=True)
Expand Down Expand Up @@ -573,7 +576,7 @@ class Application(Base, SerializeMixin):
back_populates="ownedApplications")


class Device(Base, SerializeMixin):
class Device(ModelBase):
__tablename__ = "Devices"
objectType = Column(Text)
objectId = Column(Text, primary_key=True)
Expand Down Expand Up @@ -634,7 +637,7 @@ class Device(Base, SerializeMixin):
back_populates="memberDevices")


class DirectoryRole(Base, SerializeMixin):
class DirectoryRole(ModelBase):
__tablename__ = "DirectoryRoles"
objectType = Column(Text)
objectId = Column(Text, primary_key=True)
Expand All @@ -658,7 +661,7 @@ class DirectoryRole(Base, SerializeMixin):
back_populates="memberOfRole")


class TenantDetail(Base, SerializeMixin):
class TenantDetail(ModelBase):
__tablename__ = "TenantDetails"
objectType = Column(Text)
objectId = Column(Text, primary_key=True)
Expand Down Expand Up @@ -696,7 +699,7 @@ class TenantDetail(Base, SerializeMixin):
windowsCredentialsEncryptionCertificate = Column(Text)


class ApplicationRef(Base, SerializeMixin):
class ApplicationRef(ModelBase):
__tablename__ = "ApplicationRefs"
appCategory = Column(Text)
appContextId = Column(Text)
Expand Down Expand Up @@ -724,7 +727,7 @@ class ApplicationRef(Base, SerializeMixin):
verifiedPublisher = Column(JSON)


class ExtensionProperty(Base, SerializeMixin):
class ExtensionProperty(ModelBase):
__tablename__ = "ExtensionPropertys"
objectType = Column(Text)
objectId = Column(Text, primary_key=True)
Expand All @@ -736,7 +739,7 @@ class ExtensionProperty(Base, SerializeMixin):
targetObjects = Column(JSON)


class Contact(Base, SerializeMixin):
class Contact(ModelBase):
__tablename__ = "Contacts"
objectType = Column(Text)
objectId = Column(Text, primary_key=True)
Expand Down Expand Up @@ -778,7 +781,7 @@ class Contact(Base, SerializeMixin):
back_populates="memberContacts")


class Policy(Base, SerializeMixin):
class Policy(ModelBase):
__tablename__ = "Policys"
objectType = Column(Text)
objectId = Column(Text, primary_key=True)
Expand All @@ -791,7 +794,7 @@ class Policy(Base, SerializeMixin):
tenantDefaultPolicy = Column(Integer)


class RoleDefinition(Base, SerializeMixin):
class RoleDefinition(ModelBase):
__tablename__ = "RoleDefinitions"
objectType = Column(Text)
objectId = Column(Text, primary_key=True)
Expand All @@ -811,7 +814,7 @@ class RoleDefinition(Base, SerializeMixin):
back_populates="roleDefinition")


class RoleAssignment(Base, SerializeMixin):
class RoleAssignment(ModelBase):
__tablename__ = "RoleAssignments"
id = Column(Text, primary_key=True)
principalId = Column(Text)
Expand All @@ -821,7 +824,7 @@ class RoleAssignment(Base, SerializeMixin):
back_populates="assignments")


class EligibleRoleAssignment(Base, SerializeMixin):
class EligibleRoleAssignment(ModelBase):
__tablename__ = "EligibleRoleAssignments"
id = Column(Text, primary_key=True)
principalId = Column(Text)
Expand All @@ -831,7 +834,7 @@ class EligibleRoleAssignment(Base, SerializeMixin):
back_populates="eligibleAssignments")


class AuthorizationPolicy(Base, SerializeMixin):
class AuthorizationPolicy(ModelBase):
__tablename__ = "AuthorizationPolicys"
id = Column(Text, primary_key=True)
allowInvitesFrom = Column(Text)
Expand All @@ -847,15 +850,15 @@ class AuthorizationPolicy(Base, SerializeMixin):
permissionGrantPolicyIdsAssignedToDefaultUserRole = Column(JSON)


class DirectorySetting(Base, SerializeMixin):
class DirectorySetting(ModelBase):
__tablename__ = "DirectorySettings"
id = Column(Text, primary_key=True)
displayName = Column(Text)
templateId = Column(Text)
values = Column(JSON)


class AdministrativeUnit(Base, SerializeMixin):
class AdministrativeUnit(ModelBase):
__tablename__ = "AdministrativeUnits"
objectType = Column(Text)
objectId = Column(Text, primary_key=True)
Expand Down
3 changes: 3 additions & 0 deletions roadrecon/frontend/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,8 @@
}
}
}
},
"cli": {
"analytics": false
}
}
107 changes: 79 additions & 28 deletions roadrecon/frontend/src/app/appmain/aadobjects.service.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../environments/environment'
import {HttpClient, HttpParams} from '@angular/common/http';
import { environment } from '../../environments/environment';
import {
Router, Resolve,
RouterStateSnapshot,
ActivatedRouteSnapshot
} from '@angular/router';
ActivatedRouteSnapshot, Params
} from '@angular/router';
import { Observable, of, EMPTY } from 'rxjs';
import { mergeMap, take } from 'rxjs/operators';
import {SortDirection} from '@angular/material/sort';

export interface GroupsItem {
displayName: string;
Expand Down Expand Up @@ -233,47 +234,67 @@ export interface AuthorizationPolicy {
permissionGrantPolicyIdsAssignedToDefaultUserRole: string[];
}

export interface PaginationParams {
page: number;
pageSize: number;
sortField?: string;
sortDirection?: SortDirection;
contains?: string;
}

@Injectable({
providedIn: 'root'
})
export class DatabaseService {
defaultPage = 1;
defaultPageSize = 50;

constructor(private http: HttpClient) { }

public getUsers(): Observable<UsersItem[]> {
return this.http.get<UsersItem[]>(environment.apibase + 'users');
public getUsers(pagination?: PaginationParams): Observable<UsersItem[]> {
return this.http.get<UsersItem[]>(environment.apibase + 'users', {
params: this.toHttpParams(pagination)
});
}

public getUser(id): Observable<UsersItem> {
return this.http.get<UsersItem>(environment.apibase + 'users/'+ id);
}

public getDevices(): Observable<DevicesItem[]> {
return this.http.get<DevicesItem[]>(environment.apibase + 'devices');
public getDevices(pagination?: PaginationParams): Observable<DevicesItem[]> {
return this.http.get<DevicesItem[]>(environment.apibase + 'devices',
{ params: this.toHttpParams(pagination) }
);
}

public getDevice(id): Observable<DevicesItem> {
return this.http.get<DevicesItem>(environment.apibase + 'devices/'+ id);
}

public getGroups(): Observable<GroupsItem[]> {
return this.http.get<GroupsItem[]>(environment.apibase + 'groups');
public getGroups(pagination?: PaginationParams): Observable<GroupsItem[]> {
return this.http.get<GroupsItem[]>(environment.apibase + 'groups',
{ params: this.toHttpParams(pagination) }
);
}

public getGroup(id): Observable<GroupsItem> {
return this.http.get<GroupsItem>(environment.apibase + 'groups/'+ id);
}

public getAdministrativeUnits(): Observable<AdministrativeUnitsItem[]> {
return this.http.get<AdministrativeUnitsItem[]>(environment.apibase + 'administrativeunits');
public getAdministrativeUnits(pagination?: PaginationParams): Observable<AdministrativeUnitsItem[]> {
return this.http.get<AdministrativeUnitsItem[]>(environment.apibase + 'administrativeunits',
{ params: this.toHttpParams(pagination) }
);
}

public getAdministrativeUnit(id): Observable<AdministrativeUnitsItem> {
return this.http.get<AdministrativeUnitsItem>(environment.apibase + 'administrativeunits/'+ id);
}

public getServicePrincipals(): Observable<ServicePrincipalsItem[]> {
return this.http.get<ServicePrincipalsItem[]>(environment.apibase + 'serviceprincipals');
public getServicePrincipals(pagination?: PaginationParams): Observable<ServicePrincipalsItem[]> {
return this.http.get<ServicePrincipalsItem[]>(environment.apibase + 'serviceprincipals',
{ params: this.toHttpParams(pagination) }
);
}

public getServicePrincipal(id): Observable<ServicePrincipalsItem> {
Expand All @@ -284,20 +305,26 @@ export class DatabaseService {
return this.http.get<ServicePrincipalsItem>(environment.apibase + 'serviceprincipals-by-appid/'+ id);
}

public getApplications(): Observable<ApplicationsItem[]> {
return this.http.get<ApplicationsItem[]>(environment.apibase + 'applications');
public getApplications(pagination?: PaginationParams): Observable<ApplicationsItem[]> {
return this.http.get<ApplicationsItem[]>(environment.apibase + 'applications',
{ params: this.toHttpParams(pagination) }
);
}

public getApplication(id): Observable<ApplicationsItem> {
return this.http.get<ApplicationsItem>(environment.apibase + 'applications/'+ id);
}

public getDirectoryRoles(): Observable<DirectoryRolesItem[]> {
return this.http.get<DirectoryRolesItem[]>(environment.apibase + 'directoryroles');
public getDirectoryRoles(pagination?: PaginationParams): Observable<DirectoryRolesItem[]> {
return this.http.get<DirectoryRolesItem[]>(environment.apibase + 'directoryroles',
{ params: this.toHttpParams(pagination) }
);
}

public getRoleDefinitions(): Observable<RoleDefinitionsItem[]> {
return this.http.get<RoleDefinitionsItem[]>(environment.apibase + 'roledefinitions');
public getRoleDefinitions(pagination?: PaginationParams): Observable<RoleDefinitionsItem[]> {
return this.http.get<RoleDefinitionsItem[]>(environment.apibase + 'roledefinitions',
{ params: this.toHttpParams(pagination) }
);
}

public getTenantStats(): Observable<TenantStats> {
Expand All @@ -308,12 +335,16 @@ export class DatabaseService {
return this.http.get<TenantDetail>(environment.apibase + 'tenantdetails');
}

public getAuthorizationPolicies(): Observable<AuthorizationPolicy[]> {
return this.http.get<AuthorizationPolicy[]>(environment.apibase + 'authorizationpolicies');
public getAuthorizationPolicies(pagination?: PaginationParams): Observable<AuthorizationPolicy[]> {
return this.http.get<AuthorizationPolicy[]>(environment.apibase + 'authorizationpolicies',
{ params: this.toHttpParams(pagination) }
);
}

public getAppRoles(): Observable<AppRolesItem[]> {
return this.http.get<AppRolesItem[]>(environment.apibase + 'approles');
public getAppRoles(pagination?: PaginationParams): Observable<AppRolesItem[]> {
return this.http.get<AppRolesItem[]>(environment.apibase + 'approles',
{ params: this.toHttpParams(pagination) }
);
}

public getAppRolesByResource(spid): Observable<AppRolesItem[]> {
Expand All @@ -324,12 +355,32 @@ export class DatabaseService {
return this.http.get<AppRolesItem[]>(environment.apibase + 'approles_by_principal/' + pid);
}

public getMfa(): Observable<MfaItem[]> {
return this.http.get<MfaItem[]>(environment.apibase + 'mfa');
public getMfa(pagination?: PaginationParams): Observable<MfaItem[]> {
return this.http.get<MfaItem[]>(environment.apibase + 'mfa',
{ params: this.toHttpParams(pagination) }
);
}

public getOAuth2Permissions(pagination?: PaginationParams): Observable<OAuth2PermissionsItem[]> {
return this.http.get<OAuth2PermissionsItem[]>(environment.apibase + 'oauth2permissions',
{ params: this.toHttpParams(pagination) }
);
}

public getOAuth2Permissions(): Observable<OAuth2PermissionsItem[]> {
return this.http.get<OAuth2PermissionsItem[]>(environment.apibase + 'oauth2permissions');
toHttpParams(params?: PaginationParams): HttpParams {
let httpParams = new HttpParams();
httpParams = httpParams.set('page', params?.page || this.defaultPage);
httpParams = httpParams.set('per_page', params?.pageSize || this.defaultPageSize);
if (params?.sortField) {
httpParams = httpParams.set('sort', params.sortField);
}
if (params?.sortDirection) {
httpParams = httpParams.set('direction', params.sortDirection);
}
if (params?.contains) {
httpParams = httpParams.set('contains', params.contains);
}
return httpParams;
}
}

Expand Down
5 changes: 3 additions & 2 deletions roadrecon/frontend/src/app/appmain/appmain.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import { DevicesdialogComponent } from './devices/devicesdialog/devicesdialog.co
import { JsonFormatDirective } from './json-format.directive';
import { ConfigComponent } from './config/config.component';
import { NgxWebstorageModule } from 'ngx-webstorage';
import { FormsModule } from '@angular/forms';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import { MfaComponent } from './mfa/mfa.component';
import { Oauth2permissionsComponent } from './oauth2permissions/oauth2permissions.component';

Expand Down Expand Up @@ -85,7 +85,8 @@ import { Oauth2permissionsComponent } from './oauth2permissions/oauth2permission
MatButtonModule,
MatTooltipModule,
MatSlideToggleModule,
NgxWebstorageModule.forRoot({'prefix':'RT'}),
NgxWebstorageModule.forRoot({'prefix': 'RT'}),
ReactiveFormsModule,
],
exports: [
UsersComponent,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div class="mat-elevation-z8">
<mat-form-field>
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
<input matInput [formControl]="filterControl" placeholder="Filter">
</mat-form-field>
<table mat-table class="full-width-table" matSort aria-label="Elements">
<ng-container matColumnDef="displayName">
Expand Down
Loading

0 comments on commit 1732732

Please sign in to comment.