Skip to content

Commit 681e3c5

Browse files
committed
UI improvements / Add customer filters
1 parent f03bb26 commit 681e3c5

7 files changed

Lines changed: 110 additions & 26 deletions

File tree

OpenFlow/src/DatabaseConnection.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -885,7 +885,7 @@ export class DatabaseConnection {
885885
}
886886
}
887887
if (!NoderedUtil.IsNullEmpty(user2.customerid)) {
888-
if (!user.HasRoleName("customer admins")) throw new Error("Access denied (not admin) to customer with id " + user2.customerid);
888+
if (!user.HasRoleName("customer admins") && !user.HasRoleName("admins")) throw new Error("Access denied (not admin) to customer with id " + user2.customerid);
889889
customer = await this.getbyid<Customer>(user2.customerid, "users", jwt, span)
890890
if (customer == null) throw new Error("Access denied to customer with id " + user2.customerid);
891891
} if (Config.multi_tenant && !user.HasRoleName("admins")) {
@@ -1245,6 +1245,7 @@ export class DatabaseConnection {
12451245
}
12461246
async UpdateOne<T extends Base>(q: UpdateOneMessage, parent: Span): Promise<UpdateOneMessage> {
12471247
const span: Span = Logger.otel.startSubSpan("db.UpdateOne", parent);
1248+
let customer: Customer = null;
12481249
try {
12491250
let itemReplace: boolean = true;
12501251
if (q === null || q === undefined) { throw Error("UpdateOneMessage cannot be null"); }
@@ -1279,6 +1280,21 @@ export class DatabaseConnection {
12791280
}
12801281
}
12811282
}
1283+
if (q.collectionname === "users" && (q.item._type === "user" || q.item._type === "role")) {
1284+
let user2: User = q.item as any;
1285+
if (!NoderedUtil.IsNullEmpty(user2.customerid)) {
1286+
if (!user.HasRoleName("customer admins") && !user.HasRoleName("admins")) throw new Error("Access denied (not admin) to customer with id " + user2.customerid);
1287+
customer = await this.getbyid<Customer>(user2.customerid, "users", q.jwt, span)
1288+
if (customer == null) throw new Error("Access denied to customer with id " + user2.customerid);
1289+
} if (Config.multi_tenant && !user.HasRoleName("admins")) {
1290+
throw new Error("Access denied (not admin or customer admin)");
1291+
}
1292+
if (customer != null) {
1293+
const custadmins = await this.getbyid<Role>(customer.admins, "users", q.jwt, span);
1294+
Base.addRight(q.item, custadmins._id, custadmins.name, [Rights.full_control]);
1295+
}
1296+
}
1297+
12821298
if (q.collectionname != "fs.files") {
12831299
q.item._modifiedby = user.name;
12841300
q.item._modifiedbyid = user._id;
@@ -2047,9 +2063,19 @@ export class DatabaseConnection {
20472063
return { $or: finalor.concat() };
20482064
}
20492065
private async getbasequeryuserid(userid: string, field: string, bits: number[], parent: Span): Promise<Object> {
2050-
const user = await DBHelper.FindByUsernameOrId(null, userid, parent);
2051-
const jwt = Crypt.createToken(user, Config.shorttoken_expires_in);
2052-
return this.getbasequery(jwt, field, bits);
2066+
// const user = await DBHelper.FindByUsernameOrId(null, userid, parent);
2067+
let user: User = await this.getbyid(userid, "users", Crypt.rootToken(), parent);
2068+
if (user._type == "user") {
2069+
user = await DBHelper.DecorateWithRoles(user as any, parent);
2070+
const jwt = Crypt.createToken(user as any, Config.shorttoken_expires_in);
2071+
return this.getbasequery(jwt, field, bits);
2072+
} else if (user._type == "customer") {
2073+
user = await DBHelper.DecorateWithRoles(user as any, parent);
2074+
user.roles.push(new Rolemember(user.name + " users", (user as any).users))
2075+
user.roles.push(new Rolemember(user.name + " admins", (user as any).admins))
2076+
const jwt = Crypt.createToken(user as any, Config.shorttoken_expires_in);
2077+
return this.getbasequery(jwt, field, bits);
2078+
}
20532079
}
20542080
/**
20552081
* Ensure _type and _acs on object

OpenFlow/src/public/CommonControllers.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ export class entitiesCtrl<T> {
278278
public searchfields: string[] = ["name"];
279279
public basequeryas: string = null;
280280
public errormessage: string = "";
281+
public skipcustomerfilter: boolean = false;
281282

282283
public static $inject = [
283284
"$rootScope",
@@ -362,7 +363,18 @@ export class entitiesCtrl<T> {
362363
if (this.preloadData != null) {
363364
this.preloadData();
364365
}
365-
let query: object = this.basequery;
366+
let query: object = Object.assign({}, this.basequery);
367+
if (this.collection == "users" && (this.basequery._type == "user" || this.basequery._type == "role") && !this.skipcustomerfilter) {
368+
// if (this.WebSocketClientService.user.selectedcustomerid != null) {
369+
// query["customerid"] = this.WebSocketClientService.user.selectedcustomerid;
370+
// } else if (this.WebSocketClientService.user.customerid != null) {
371+
// query["customerid"] = this.WebSocketClientService.user.customerid;
372+
// }
373+
}
374+
let basequeryas = this.basequeryas;
375+
if (!NoderedUtil.IsNullUndefinded(this.WebSocketClientService.customer) && !this.skipcustomerfilter) {
376+
basequeryas = this.WebSocketClientService.customer._id;
377+
}
366378
if (this.searchstring !== "" && this.searchstring != null) {
367379
if ((this.searchstring as string).indexOf("{") == 0) {
368380
if ((this.searchstring as string).lastIndexOf("}") == ((this.searchstring as string).length - 1)) {
@@ -394,7 +406,7 @@ export class entitiesCtrl<T> {
394406

395407
}
396408
}
397-
this.models = await NoderedUtil.Query(this.collection, query, this.baseprojection, this.orderby, this.pagesize, 0, null, this.basequeryas,
409+
this.models = await NoderedUtil.Query(this.collection, query, this.baseprojection, this.orderby, this.pagesize, 0, null, basequeryas,
398410
null, 2);
399411
this.loading = false;
400412
if (this.autorefresh) {

OpenFlow/src/public/Controllers.ts

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,14 @@ export class MenuCtrl {
8787
this.signedin = true;
8888

8989
this.customers = await NoderedUtil.Query("users", { _type: "customer" }, null, null, 100, 0, null, null, null, 2);
90-
if (this.customers.length == 1) this.customer = this.customers[0];
91-
if (this.customers.length > 1 && (data.customerid != null || data.selectedcustomerid != null)) {
92-
this.customer = null;
93-
if (data.selectedcustomerid != null) {
90+
this.customer = null;
91+
if (this.customers.length > 0 && (this.user.selectedcustomerid != null)) {
92+
if (this.user.selectedcustomerid != null) {
9493
for (let cust of this.customers)
95-
if (cust._id == data.selectedcustomerid) this.customer = cust;
96-
}
97-
if (this.customer == null) {
98-
for (let cust of this.customers)
99-
if (cust._id == data.customerid) this.customer = cust;
100-
94+
if (cust._id == this.user.selectedcustomerid) this.customer = cust;
10195
}
10296
}
97+
this.WebSocketClientService.customer = this.customer as any;
10398
if (!this.$scope.$$phase) { this.$scope.$apply(); }
10499
// cleanup();
105100
});
@@ -111,15 +106,11 @@ export class MenuCtrl {
111106
this.$scope.$on('menurefresh', async (event, data) => {
112107
if (event && data) { }
113108
this.customers = await NoderedUtil.Query("users", { _type: "customer" }, null, null, 100, 0, null, null, null, 2);
114-
if (this.customers.length == 1) this.customer = this.customers[0];
115-
if (this.customers.length > 1 && data.customerid != null) {
116-
for (let cust of this.customers)
117-
if (cust._id == data.customerid) this.customer = cust;
118-
}
119-
if (this.customers.length > 1 && data.selectedcustomerid != null) {
109+
if (this.customers.length > 0 && this.user.selectedcustomerid != null) {
120110
for (let cust of this.customers)
121-
if (cust._id == data.selectedcustomerid) this.customer = cust;
111+
if (cust._id == this.user.selectedcustomerid) this.customer = cust;
122112
}
113+
this.WebSocketClientService.customer = this.customer as any;
123114
if (!this.$scope.$$phase) { this.$scope.$apply(); }
124115
});
125116
}
@@ -150,6 +141,27 @@ export class MenuCtrl {
150141
Search() {
151142
this.$rootScope.$broadcast("search", this.searchstring);
152143
}
144+
SelectCustomer(customer) {
145+
if (customer != null) {
146+
if (this.WebSocketClientService.user.customerid == customer._id) {
147+
this.WebSocketClientService.user.selectedcustomerid = null;
148+
} else {
149+
this.WebSocketClientService.user.selectedcustomerid = customer._id;
150+
}
151+
this.WebSocketClientService.customer = customer as any;
152+
this.$rootScope.$broadcast("menurefresh");
153+
this.$rootScope.$broadcast("search", this.searchstring);
154+
if (this.PathIs("/Customer")) {
155+
this.$location.path("/Customer/" + customer._id);
156+
if (!this.$scope.$$phase) { this.$scope.$apply(); }
157+
}
158+
} else {
159+
this.WebSocketClientService.user.selectedcustomerid = null;
160+
this.WebSocketClientService.customer = null;
161+
this.$rootScope.$broadcast("menurefresh");
162+
this.$rootScope.$broadcast("search", this.searchstring);
163+
}
164+
}
153165
}
154166
export class RPAWorkflowCtrl extends entityCtrl<RPAWorkflow> {
155167
public arguments: any;
@@ -1128,6 +1140,7 @@ export class UsersCtrl extends entitiesCtrl<TokenUser> {
11281140
this.orderby = this.userdata.data.UsersCtrl.orderby;
11291141
this.searchstring = this.userdata.data.UsersCtrl.searchstring;
11301142
this.basequeryas = this.userdata.data.UsersCtrl.basequeryas;
1143+
this.skipcustomerfilter = this.userdata.data.UsersCtrl.skipcustomerfilter;
11311144
}
11321145

11331146
WebSocketClientService.onSignedin((user: TokenUser) => {
@@ -1142,6 +1155,7 @@ export class UsersCtrl extends entitiesCtrl<TokenUser> {
11421155
this.userdata.data.UsersCtrl.orderby = this.orderby;
11431156
this.userdata.data.UsersCtrl.searchstring = this.searchstring;
11441157
this.userdata.data.UsersCtrl.basequeryas = this.basequeryas;
1158+
this.userdata.data.UsersCtrl.skipcustomerfilter = this.skipcustomerfilter;
11451159
this.loading = false;
11461160
if (!this.$scope.$$phase) { this.$scope.$apply(); }
11471161
}
@@ -1297,6 +1311,7 @@ export class RolesCtrl extends entitiesCtrl<Role> {
12971311
this.orderby = this.userdata.data.RolesCtrl.orderby;
12981312
this.searchstring = this.userdata.data.RolesCtrl.searchstring;
12991313
this.basequeryas = this.userdata.data.RolesCtrl.basequeryas;
1314+
this.skipcustomerfilter = this.userdata.data.RolesCtrl.skipcustomerfilter;
13001315
}
13011316
WebSocketClientService.onSignedin((user: TokenUser) => {
13021317
this.loadData();
@@ -1310,6 +1325,7 @@ export class RolesCtrl extends entitiesCtrl<Role> {
13101325
this.userdata.data.RolesCtrl.orderby = this.orderby;
13111326
this.userdata.data.RolesCtrl.searchstring = this.searchstring;
13121327
this.userdata.data.RolesCtrl.basequeryas = this.basequeryas;
1328+
this.userdata.data.RolesCtrl.skipcustomerfilter = this.skipcustomerfilter;
13131329
if (!this.$scope.$$phase) { this.$scope.$apply(); }
13141330
}
13151331
}
@@ -4951,6 +4967,12 @@ export class CustomerCtrl extends entityCtrl<Customer> {
49514967
async processdata() {
49524968
try {
49534969
// this.stripe_customer = await NoderedUtil.EnsureStripeCustomer(this.model, this.userid, null, 2);
4970+
if (this.model != null) {
4971+
if (this.WebSocketClientService.user.selectedcustomerid != this.model._id) {
4972+
this.WebSocketClientService.user.selectedcustomerid = this.model._id;
4973+
this.$rootScope.$broadcast("menurefresh");
4974+
}
4975+
}
49544976

49554977
} catch (error) {
49564978

OpenFlow/src/public/Roles.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
<h1 translate lib="web">roles</h1>
33
</div>
44
<div class="col-sm-12 text-right">
5+
<input type="checkbox" id="checkbox-1" ng-model="ctrl.skipcustomerfilter" ng-change="ctrl.Search()">
6+
<label for="checkbox-1"><span translate lib="web">show all</span></label>
57
<a href="#/Role" class="btn" translate lib="web">addrole</a>
68
</div>
79
<div ng-show="ctrl.errormessage != ''"" class=" alert alert-danger" role="alert">{{ctrl.errormessage}}</div>

OpenFlow/src/public/Users.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
<div class="row">
22
<h1 translate lib="web">users</h1>
33
</div>
4+
45
<div class="col-sm-12 text-right">
6+
<input type="checkbox" id="checkbox-1" ng-model="ctrl.skipcustomerfilter" ng-change="ctrl.Search()">
7+
<label for="checkbox-1"><span translate lib="web">show all</span></label>
58
<a href="#/User" class="btn btn-info" translate lib="web">Adduser</a>
69
</div>
710
<div ng-show="ctrl.errormessage != ''"" class=" alert alert-danger" role="alert">{{ctrl.errormessage}}</div>

OpenFlow/src/public/WebSocketClientService.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { WebSocketClient, TokenUser, NoderedUtil } from "@openiap/openflow-api";
1+
import { WebSocketClient, TokenUser, NoderedUtil, Customer } from "@openiap/openflow-api";
22

33
interface IHashTable<T> {
44
[key: string]: T;
@@ -144,6 +144,7 @@ export class WebSocketClientService {
144144
debug(msg) { console.debug(msg); },
145145
silly(msg) { console.debug(msg); }
146146
}
147+
public customer: Customer = null;
147148
public user: TokenUser = null;
148149
public jwt: string = null;
149150
public version: string = "";

OpenFlow/src/public/index.html

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,26 @@
116116
<i class="fa fa-angle-down" aria-hidden="true"></i>
117117
</button>
118118
<div class="dropdown-menu dropdown-menu-right w-200" aria-labelledby="navbar-dropdown-toggle-btn-1">
119-
<a class="dropdown-item" ng-href="#/Customer/{{model._id}}"
120-
ng-repeat="model in menuctrl.customers">{{model.name}}</a>
119+
<div class="row" ng-show="menuctrl.customer != null">
120+
<div class="col-sm text-left text-nowrap w-100">
121+
<a href ng-click="menuctrl.SelectCustomer(null)" class="dropdown-item">No filter</a>
122+
</div>
123+
<div class="col-sm text-right w-90">
124+
<a ng-href="#/Customer/{{model._id}}" ng-show="menuctrl.hasrole('customer admins')">
125+
<em class="fas fa-money-bill-wave"></em></a>
126+
</div>
127+
</div>
128+
<div class="row" ng-repeat="model in menuctrl.customers">
129+
<div class="col-sm text-left text-nowrap w-100">
130+
<a href ng-click="menuctrl.SelectCustomer(model)" class="dropdown-item">{{model.name}}</a>
131+
</div>
132+
<div class="col-sm text-right w-90">
133+
<a ng-href="#/Customer/{{model._id}}" ng-show="menuctrl.hasrole('customer admins')">
134+
<em class="fas fa-money-bill-wave"></em></a>
135+
</div>
136+
</div>
137+
<!-- <a class="dropdown-item" ng-href="#/Customer/{{model._id}}"
138+
ng-repeat="model in menuctrl.customers">{{model.name}}</a> -->
121139
</div>
122140
</div>
123141
<!-- remove -->

0 commit comments

Comments
 (0)