This commit is contained in:
		
							
								
								
									
										14
									
								
								jasmine.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								jasmine.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
|  | ||||
| { | ||||
|   "spec_dir": "test", | ||||
|   "spec_files": [ | ||||
|     "spec/*.js", | ||||
|     "spec/*.ts" | ||||
|   ], | ||||
|   "helpers": [ | ||||
|     "helpers/*.js", | ||||
|     "helpers/*.ts" | ||||
|   ], | ||||
|   "stopSpecOnExpectationFailure": false, | ||||
|   "random": false | ||||
| } | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| export type ErrorCallback = ( | ||||
|   option: string, | ||||
|   value: unknown, | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { TypeValidation } from '../TypeValidation/TypeValidation'; | ||||
| import { BaseOption } from './BaseOption'; | ||||
|  | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { OptionSource } from '../Sources/OptionSource'; | ||||
| import { Option, OptionValue } from '../Option'; | ||||
| import { EnvSource } from '../Sources/EnvSource'; | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { TypeValidation } from '../TypeValidation/TypeValidation'; | ||||
| import { BaseOption } from './BaseOption'; | ||||
|  | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { PathType } from '../TypeValidation/PathType'; | ||||
| import { TypeValidation } from '../TypeValidation/TypeValidation'; | ||||
| import { StringOption } from './StringOption'; | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { PathType } from '../TypeValidation/PathType'; | ||||
| import { TypeValidation } from '../TypeValidation/TypeValidation'; | ||||
| import { StringOption } from './StringOption'; | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { TypeValidation } from '../TypeValidation/TypeValidation'; | ||||
| import { BaseOption } from './BaseOption'; | ||||
|  | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { TypeValidation } from '../TypeValidation/TypeValidation'; | ||||
| import { BaseOption } from './BaseOption'; | ||||
|  | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { PathType } from '../TypeValidation/PathType'; | ||||
| import { TypeValidation } from '../TypeValidation/TypeValidation'; | ||||
| import { StringOption } from './StringOption'; | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { TypeValidation } from '../TypeValidation/TypeValidation'; | ||||
| import { StringOptionConfig } from '../SubConfigs'; | ||||
| import { BaseOption } from './BaseOption'; | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { List } from 'enquirer'; | ||||
| import { InteractiveSubSource } from './InteractiveSubSource'; | ||||
|  | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { Confirm } from 'enquirer'; | ||||
| import { InteractiveSubSource } from './InteractiveSubSource'; | ||||
|  | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { OptionValue, Option } from '../../Option'; | ||||
|  | ||||
| export abstract class InteractiveSubSource { | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { NumberPrompt } from 'enquirer'; | ||||
| import { InteractiveSubSource } from './InteractiveSubSource'; | ||||
|  | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { AutoComplete } from 'enquirer'; | ||||
| import { StringOptionConfig } from '../../SubConfigs'; | ||||
| import { InteractiveSubSource } from './InteractiveSubSource'; | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { Input } from 'enquirer'; | ||||
| import { InteractiveSubSource } from './InteractiveSubSource'; | ||||
|  | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { ArraySubSource } from './ArraySubSource'; | ||||
| import { BooleanSubSource } from './BooleanSubSource'; | ||||
| import { PresetSubSource } from './PresetSubSource'; | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { Option } from './Option'; | ||||
|  | ||||
| interface StringOptionConfig extends Option { | ||||
|   | ||||
							
								
								
									
										12
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "@sapphirecode/console-app", | ||||
|   "version": "2.1.6", | ||||
|   "version": "2.1.7", | ||||
|   "main": "dist/lib/index.js", | ||||
|   "author": { | ||||
|     "name": "Timo Hocker", | ||||
| @@ -14,19 +14,21 @@ | ||||
|   "bugs": "https://redmine.scode.ovh/projects/console-app", | ||||
|   "description": "read parameters from env, config files, console args or interactively", | ||||
|   "devDependencies": { | ||||
|     "@ava/typescript": "^1.1.1", | ||||
|     "@sapphirecode/eslint-config-ts": "^1.1.4", | ||||
|     "@types/fs-extra": "^9.0.0", | ||||
|     "@types/hjson": "^2.4.1", | ||||
|     "@types/jasmine": "^3.5.14", | ||||
|     "@types/yargs": "^15.0.5", | ||||
|     "ava": "^3.8.2", | ||||
|     "eslint": "^7.0.0", | ||||
|     "jasmine": "^3.6.1", | ||||
|     "jasmine-ts": "^0.3.0", | ||||
|     "nyc": "^15.0.1", | ||||
|     "ts-node": "^9.0.0", | ||||
|     "typescript": "^4.0.2" | ||||
|   }, | ||||
|   "scripts": { | ||||
|     "lint": "eslint . --ext .js,.jsx,.ts,.tsx,.vue,.mjs", | ||||
|     "test": "tsc && nyc ava", | ||||
|     "test": "nyc jasmine-ts --config=\"jasmine.json\"", | ||||
|     "compile": "tsc" | ||||
|   }, | ||||
|   "files": [ | ||||
| @@ -50,4 +52,4 @@ | ||||
|     "environment variables", | ||||
|     "parsing" | ||||
|   ] | ||||
| } | ||||
| } | ||||
| @@ -1,46 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, May 2020 | ||||
|  */ | ||||
|  | ||||
| import test from 'ava'; | ||||
| import { PathType } from '../lib/TypeValidation/PathType'; | ||||
|  | ||||
| test ('no file', async (t) => { | ||||
|   const validator = new PathType ('file'); | ||||
|   await t.throwsAsync ( | ||||
|     () => validator.to_type ('test'), | ||||
|     { message: 'cannot assign folder to file' } | ||||
|   ); | ||||
| }); | ||||
| test ('file', async (t) => { | ||||
|   const validator = new PathType ('file'); | ||||
|   const res = await validator.to_type ('package.json'); | ||||
|   t.is (res, 'package.json'); | ||||
| }); | ||||
| test ('no folder', async (t) => { | ||||
|   const validator = new PathType ('folder'); | ||||
|   await t.throwsAsync ( | ||||
|     () => validator.to_type ('package.json'), | ||||
|     { message: 'cannot assign folder to file' } | ||||
|   ); | ||||
| }); | ||||
| test ('folder', async (t) => { | ||||
|   const validator = new PathType ('folder'); | ||||
|   const res = await validator.to_type ('test'); | ||||
|   t.is (res, 'test'); | ||||
| }); | ||||
| test ('no path', async (t) => { | ||||
|   const validator = new PathType ('path'); | ||||
|   await t.throwsAsync ( | ||||
|     () => validator.to_type ('doesnotexist.file'), | ||||
|     { message: 'path does not exist' } | ||||
|   ); | ||||
| }); | ||||
| test ('path', async (t) => { | ||||
|   const validator = new PathType ('path'); | ||||
|   const res = await validator.to_type ('test'); | ||||
|   t.is (res, 'test'); | ||||
| }); | ||||
| @@ -1,91 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, May 2020 | ||||
|  */ | ||||
|  | ||||
| import test from 'ava'; | ||||
| import { TypeValidation } from '../lib/TypeValidation/TypeValidation'; | ||||
|  | ||||
| test ('string', async (t) => { | ||||
|   const validator = new TypeValidation ('string'); | ||||
|   const res = await validator.to_type ('foo'); | ||||
|   t.is (res, 'foo'); | ||||
| }); | ||||
|  | ||||
| test ('no number', (t) => { | ||||
|   const validator = new TypeValidation ('number'); | ||||
|   t.throws ( | ||||
|     () => validator.to_type ('foo'), | ||||
|     { message: 'value is not a number' } | ||||
|   ); | ||||
| }); | ||||
|  | ||||
| test ('number', async (t) => { | ||||
|   const validator = new TypeValidation ('number'); | ||||
|   const res = await validator.to_type ('123.4'); | ||||
|   t.is (res, 123.4); | ||||
| }); | ||||
|  | ||||
| test ('int', async (t) => { | ||||
|   const validator = new TypeValidation ('int'); | ||||
|   const res = await validator.to_type ('123.4'); | ||||
|   t.is (res, 123); | ||||
| }); | ||||
|  | ||||
| test ('no boolean', (t) => { | ||||
|   const validator = new TypeValidation ('boolean'); | ||||
|   t.throws ( | ||||
|     () => validator.to_type ('foo'), | ||||
|     { message: 'value is not a boolean' } | ||||
|   ); | ||||
| }); | ||||
|  | ||||
| test ('boolean', async (t) => { | ||||
|   const validator = new TypeValidation ('boolean'); | ||||
|   const r1 = await validator.to_type ('false'); | ||||
|   const r2 = await validator.to_type ('true'); | ||||
|   t.is (r1, false); | ||||
|   t.is (r2, true); | ||||
| }); | ||||
|  | ||||
| test ('boolean number', async (t) => { | ||||
|   const validator = new TypeValidation ('boolean'); | ||||
|   const r1 = await validator.to_type (0); | ||||
|   const r2 = await validator.to_type (1); | ||||
|   t.is (r1, false); | ||||
|   t.is (r2, true); | ||||
| }); | ||||
|  | ||||
| test ('no array', (t) => { | ||||
|   const validator = new TypeValidation ('array'); | ||||
|   t.throws ( | ||||
|     () => validator.to_type (1), | ||||
|     { message: 'value is not an array' } | ||||
|   ); | ||||
| }); | ||||
|  | ||||
| test ('array', async (t) => { | ||||
|   const validator = new TypeValidation ('array'); | ||||
|   const res = await validator.to_type ([ | ||||
|     'foo', | ||||
|     'bar', | ||||
|     'baz' | ||||
|   ]); | ||||
|   t.deepEqual (res, [ | ||||
|     'foo', | ||||
|     'bar', | ||||
|     'baz' | ||||
|   ]); | ||||
| }); | ||||
|  | ||||
| test ('string array', async (t) => { | ||||
|   const validator = new TypeValidation ('array'); | ||||
|   const res = await validator.to_type ('f o o,bar  ,  baz'); | ||||
|   t.deepEqual (res, [ | ||||
|     'f o o', | ||||
|     'bar', | ||||
|     'baz' | ||||
|   ]); | ||||
| }); | ||||
							
								
								
									
										46
									
								
								test/spec/paths.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								test/spec/paths.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { PathType } from '../../lib/TypeValidation/PathType'; | ||||
|  | ||||
| describe ('paths', () => { | ||||
|   it ('no file', async () => { | ||||
|     const validator = new PathType ('file'); | ||||
|     await expectAsync ( | ||||
|       validator.to_type ('test') | ||||
|     ) | ||||
|       .toBeRejectedWithError ('cannot assign folder to file'); | ||||
|   }); | ||||
|   it ('file', async () => { | ||||
|     const validator = new PathType ('file'); | ||||
|     const res = await validator.to_type ('package.json'); | ||||
|     expect (res) | ||||
|       .toEqual ('package.json'); | ||||
|   }); | ||||
|   it ('no folder', async () => { | ||||
|     const validator = new PathType ('folder'); | ||||
|     await expectAsync (validator.to_type ('package.json')) | ||||
|       .toBeRejectedWithError ('cannot assign folder to file'); | ||||
|   }); | ||||
|   it ('folder', async () => { | ||||
|     const validator = new PathType ('folder'); | ||||
|     const res = await validator.to_type ('test'); | ||||
|     expect (res) | ||||
|       .toEqual ('test'); | ||||
|   }); | ||||
|   it ('no path', async () => { | ||||
|     const validator = new PathType ('path'); | ||||
|     await expectAsync (validator.to_type ('doesnotexist.file')) | ||||
|       .toBeRejectedWithError ('path does not exist'); | ||||
|   }); | ||||
|   it ('path', async () => { | ||||
|     const validator = new PathType ('path'); | ||||
|     const res = await validator.to_type ('test'); | ||||
|     expect (res) | ||||
|       .toEqual ('test'); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										102
									
								
								test/spec/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								test/spec/types.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | ||||
| /* | ||||
|  * Copyright (C) Sapphirecode - All Rights Reserved | ||||
|  * This file is part of console-app which is released under MIT. | ||||
|  * See file 'LICENSE' for full license details. | ||||
|  * Created by Timo Hocker <timo@scode.ovh>, October 2020 | ||||
|  */ | ||||
|  | ||||
| import { TypeValidation } from '../../lib/TypeValidation/TypeValidation'; | ||||
|  | ||||
| // eslint-disable-next-line max-lines-per-function | ||||
| describe ('type validation', () => { | ||||
|   it ('string', async () => { | ||||
|     const validator = new TypeValidation ('string'); | ||||
|     const res = await validator.to_type ('foo'); | ||||
|     expect (res) | ||||
|       .toEqual ('foo'); | ||||
|   }); | ||||
|  | ||||
|   it ('no number', () => { | ||||
|     const validator = new TypeValidation ('number'); | ||||
|     expect ( | ||||
|       () => validator.to_type ('foo') | ||||
|     ) | ||||
|       .toThrowError ('value is not a number'); | ||||
|   }); | ||||
|  | ||||
|   it ('number', async () => { | ||||
|     const validator = new TypeValidation ('number'); | ||||
|     const res = await validator.to_type ('123.4'); | ||||
|     expect (res) | ||||
|       .toEqual (123.4); | ||||
|   }); | ||||
|  | ||||
|   it ('int', async () => { | ||||
|     const validator = new TypeValidation ('int'); | ||||
|     const res = await validator.to_type ('123.4'); | ||||
|     expect (res) | ||||
|       .toEqual (123); | ||||
|   }); | ||||
|  | ||||
|   it ('no boolean', () => { | ||||
|     const validator = new TypeValidation ('boolean'); | ||||
|     expect ( | ||||
|       () => validator.to_type ('foo') | ||||
|     ) | ||||
|       .toThrowError ('value is not a boolean'); | ||||
|   }); | ||||
|  | ||||
|   it ('boolean', async () => { | ||||
|     const validator = new TypeValidation ('boolean'); | ||||
|     const r1 = await validator.to_type ('false'); | ||||
|     const r2 = await validator.to_type ('true'); | ||||
|     expect (r1) | ||||
|       .toEqual (false); | ||||
|     expect (r2) | ||||
|       .toEqual (true); | ||||
|   }); | ||||
|  | ||||
|   it ('boolean number', async () => { | ||||
|     const validator = new TypeValidation ('boolean'); | ||||
|     const r1 = await validator.to_type (0); | ||||
|     const r2 = await validator.to_type (1); | ||||
|     expect (r1) | ||||
|       .toEqual (false); | ||||
|     expect (r2) | ||||
|       .toEqual (true); | ||||
|   }); | ||||
|  | ||||
|   it ('no array', () => { | ||||
|     const validator = new TypeValidation ('array'); | ||||
|     expect ( | ||||
|       () => validator.to_type (1) | ||||
|     ) | ||||
|       .toThrowError ('value is not an array'); | ||||
|   }); | ||||
|  | ||||
|   it ('array', async () => { | ||||
|     const validator = new TypeValidation ('array'); | ||||
|     const res = await validator.to_type ([ | ||||
|       'foo', | ||||
|       'bar', | ||||
|       'baz' | ||||
|     ]); | ||||
|     expect (res) | ||||
|       .toEqual ([ | ||||
|         'foo', | ||||
|         'bar', | ||||
|         'baz' | ||||
|       ]); | ||||
|   }); | ||||
|  | ||||
|   it ('string array', async () => { | ||||
|     const validator = new TypeValidation ('array'); | ||||
|     const res = await validator.to_type ('f o o,bar  ,  baz'); | ||||
|     expect (res) | ||||
|       .toEqual ([ | ||||
|         'f o o', | ||||
|         'bar', | ||||
|         'baz' | ||||
|       ]); | ||||
|   }); | ||||
| }); | ||||
		Reference in New Issue
	
	Block a user