Skip to content

Commit 5638ea5

Browse files
authored
Merge pull request #190 from StatelessStudio/v3.2.0
[3.2.0] Aug-19-2019
2 parents 0d9eaed + f9c3983 commit 5638ea5

5 files changed

Lines changed: 198 additions & 38 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# PointyApi Changelog
22

3+
## [3.2.0] Aug-19-2019
4+
5+
### Additions
6+
- [Issue #189] Add CanReadAll() and CanWriteAll()
7+
8+
### Fixes
9+
- npm update
10+
311
## [3.1.0] Aug-06-2019
412

513
### Additions

package-lock.json

Lines changed: 26 additions & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "pointyapi",
3-
"version": "3.1.0",
3+
"version": "3.2.0",
44
"author": "stateless-studio",
55
"license": "MIT",
66
"scripts": {
@@ -24,9 +24,9 @@
2424
"dependencies": {
2525
"@types/atob": "^2.1.2",
2626
"@types/btoa": "^1.2.3",
27-
"@types/express": "^4.17.0",
27+
"@types/express": "^4.17.1",
2828
"@types/jsonwebtoken": "^7.2.8",
29-
"@types/node": "^10.14.14",
29+
"@types/node": "^10.14.15",
3030
"@types/request": "^2.48.2",
3131
"atob": "^2.1.2",
3232
"bcryptjs": "^2.4.3",
@@ -35,7 +35,7 @@
3535
"express": "^4.17.1",
3636
"jsonwebtoken": "^8.5.1",
3737
"mock-req-res": "^1.1.1",
38-
"pg": "^7.12.0",
38+
"pg": "^7.12.1",
3939
"pg-connection-string": "^2.1.0",
4040
"reflect-metadata": "^0.1.13",
4141
"request": "^2.88.0",
@@ -48,7 +48,7 @@
4848
"devDependencies": {
4949
"@istanbuljs/nyc-config-typescript": "^0.1.3",
5050
"@types/jasmine": "^2.8.16",
51-
"coveralls": "^3.0.5",
51+
"coveralls": "^3.0.6",
5252
"jasmine": "^3.4.0",
5353
"nyc": "^14.1.1",
5454
"source-map-support": "^0.5.13",

src/bodyguard.ts

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,18 +130,70 @@
130130
*/
131131

132132
/**
133-
* Bodyguard Decorators
133+
* # Bodyguard Decorators
134134
*/
135135
import 'reflect-metadata';
136136
import { BodyguardOwner, UserRole } from './enums';
137137

138+
const CanReadAllSymbol = Symbol('CanReadAll');
139+
const CanWriteAllSymbol = Symbol('CanWriteAll');
138140
const CanReadSymbol = Symbol('CanRead');
139141
const CanWriteSymbol = Symbol('CanWrite');
140142
const BodyguardKeySymbol = Symbol('BodyguardKey');
141143
const CanSearchSymbol = Symbol('CanSearch');
142144
const CanSearchRelationSymbol = Symbol('CanSearchRelation');
143145
const CanReadRelationSymbol = Symbol('CanReadRelationSymbol');
144146

147+
/**
148+
* ## Class Decorators
149+
*/
150+
151+
/**
152+
* Get if all members are readable
153+
* NOTE: This function only checks if the CanReadAll() decorator is present.
154+
* Individual fields may have fine-grain access rights, which this
155+
* function will ignore. Use getCanRead() instead for authorization.
156+
* @param target Object to test
157+
*/
158+
export function getCanReadAll(target: any): string {
159+
return Reflect.getMetadata(CanReadAllSymbol, target.constructor);
160+
}
161+
162+
/**
163+
* Get if all members are writableF
164+
* NOTE: This function only checks if the CanWriteAll() decorator is present.
165+
* Individual fields may have fine-grain access rights, which this
166+
* function will ignore. Use getCanWrite() instead for authorization.
167+
* @param target Object to test
168+
*/
169+
export function getCanWriteAll(target: any): string {
170+
return Reflect.getMetadata(CanWriteAllSymbol, target.constructor);
171+
}
172+
173+
/**
174+
* All class members are readable
175+
* @param who Who can read the fields. Default is anyone
176+
*/
177+
export function CanReadAll(
178+
who: BodyguardOwner | UserRole = BodyguardOwner.Anyone
179+
) {
180+
return Reflect.metadata(CanReadAllSymbol, who);
181+
}
182+
183+
/**
184+
* All class members are readable
185+
* @param who Who can read the fields. Default is anyone
186+
*/
187+
export function CanWriteAll(
188+
who: BodyguardOwner | UserRole = BodyguardOwner.Anyone
189+
) {
190+
return Reflect.metadata(CanWriteAllSymbol, who);
191+
}
192+
193+
/**
194+
* ## Member Decorators
195+
*/
196+
145197
/**
146198
* Check if the key is a bodyguard key
147199
* @param target Object to test
@@ -157,7 +209,10 @@ export function isBodyguardKey(target: any, propertyKey: string): boolean {
157209
* @param propertyKey Key to check
158210
*/
159211
export function getCanRead(target: any, propertyKey: string): string {
160-
return Reflect.getMetadata(CanReadSymbol, target, propertyKey);
212+
return (
213+
Reflect.getMetadata(CanReadSymbol, target, propertyKey) ||
214+
getCanReadAll(target)
215+
);
161216
}
162217

163218
/**
@@ -166,7 +221,10 @@ export function getCanRead(target: any, propertyKey: string): string {
166221
* @param propertyKey Key to check
167222
*/
168223
export function getCanWrite(target: any, propertyKey: string): string {
169-
return Reflect.getMetadata(CanWriteSymbol, target, propertyKey);
224+
return (
225+
Reflect.getMetadata(CanWriteSymbol, target, propertyKey) ||
226+
getCanWriteAll(target)
227+
);
170228
}
171229

172230
/**

test/spec/api/bodyguard/bodyguard.spec.ts

Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ import {
1414
CanRead,
1515
CanWrite,
1616
CanSearch,
17-
CanSearchRelation
17+
CanSearchRelation,
18+
CanReadAll,
19+
CanWriteAll,
20+
getCanReadAll,
21+
getCanWriteAll
1822
} from '../../../../src/bodyguard';
1923
import { BaseModel } from '../../../../src/models';
20-
import { BodyguardOwner } from '../../../../src/enums';
24+
import { BodyguardOwner, UserRole } from '../../../../src/enums';
2125

2226
class ExampleModel extends BaseModel {
2327
@BodyguardKey() public bodyguardKey: number = undefined;
@@ -48,6 +52,76 @@ class ExampleModel extends BaseModel {
4852
}
4953
const example = new ExampleModel();
5054

55+
@CanReadAll()
56+
class ExampleReadableModel extends BaseModel {
57+
public testField1: string = undefined;
58+
}
59+
const exampleReadable = new ExampleReadableModel();
60+
61+
@CanWriteAll()
62+
class ExampleWritableModel extends BaseModel {
63+
public testField1: string = undefined;
64+
}
65+
const exampleWritable = new ExampleWritableModel();
66+
67+
@CanReadAll(UserRole.Admin)
68+
class AdminReadableModel extends BaseModel {
69+
public testField1: string = undefined;
70+
}
71+
const adminReadable = new AdminReadableModel();
72+
73+
@CanWriteAll(UserRole.Admin)
74+
class AdminWritableModel extends BaseModel {
75+
public testField1: string = undefined;
76+
}
77+
const adminWritable = new AdminWritableModel();
78+
79+
@CanReadAll()
80+
class MixedReadableModel extends BaseModel {
81+
public anyoneCanReadThisField: string = undefined;
82+
83+
@CanRead(UserRole.Admin)
84+
public butOnlyAdminCanReadThisOne: string = undefined;
85+
}
86+
const mixedReadable = new MixedReadableModel();
87+
88+
@CanWriteAll()
89+
class MixedWritableModel extends BaseModel {
90+
public anyoneCanWriteThisField: string = undefined;
91+
92+
@CanWrite(UserRole.Admin)
93+
public butOnlyAdminCanWriteThisOne: string = undefined;
94+
}
95+
const mixedWritable = new MixedWritableModel();
96+
97+
/**
98+
* getCanReadAll()
99+
* pointyapi/bodyguard
100+
*/
101+
describe('getCanReadAll()', () => {
102+
it('returns anyone if no parameter is set', () => {
103+
expect(getCanReadAll(exampleReadable)).toEqual(BodyguardOwner.Anyone);
104+
});
105+
106+
it('returns role if set as parameter', () => {
107+
expect(getCanReadAll(adminReadable)).toEqual(UserRole.Admin);
108+
});
109+
});
110+
111+
/**
112+
* getCanWriteAll()
113+
* pointyapi/bodyguard
114+
*/
115+
describe('getCanWriteAll()', () => {
116+
it('returns anyone if no parameter is set', () => {
117+
expect(getCanWriteAll(exampleWritable)).toEqual(BodyguardOwner.Anyone);
118+
});
119+
120+
it('returns role if set as parameter', () => {
121+
expect(getCanWriteAll(adminWritable)).toEqual(UserRole.Admin);
122+
});
123+
});
124+
51125
/**
52126
* isBodyguardKey()
53127
* pointyapi/bodyguard
@@ -91,8 +165,16 @@ describe('getCanRead()', () => {
91165
);
92166
});
93167

94-
it('returns undefined if the member is not readable', () => {
95-
expect(getCanRead(example, 'bodyguardKey')).toBe(undefined);
168+
it('returns anyone if the class has CanReadAll()', () => {
169+
expect(getCanRead(mixedReadable, 'anyoneCanReadThisField')).toEqual(
170+
BodyguardOwner.Anyone
171+
);
172+
});
173+
174+
it('returns UserRole.Admin if CanReadAll() has been overridden', () => {
175+
expect(getCanRead(mixedReadable, 'butOnlyAdminCanReadThisOne')).toEqual(
176+
UserRole.Admin
177+
);
96178
});
97179
});
98180

@@ -128,6 +210,18 @@ describe('getCanWrite()', () => {
128210
it('returns undefined if the member is not writeable', () => {
129211
expect(getCanWrite(example, 'bodyguardKey')).toBe(undefined);
130212
});
213+
214+
it('returns anyone if the class has CanWriteAll()', () => {
215+
expect(getCanWrite(mixedWritable, 'anyoneCanWriteThisField')).toEqual(
216+
BodyguardOwner.Anyone
217+
);
218+
});
219+
220+
it('returns UserRole.Admin if CanWriteAll() has been overridden', () => {
221+
expect(
222+
getCanWrite(mixedWritable, 'butOnlyAdminCanWriteThisOne')
223+
).toEqual(UserRole.Admin);
224+
});
131225
});
132226

133227
/**

0 commit comments

Comments
 (0)