mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2025-12-27 10:33:59 -05:00
Library updates and lint fixes (#8099)
* Minor updates only * Added explicit radix parameter (10) to all Number.parseInt() calls throughout the codebase (new lint rule) * Updated several @ts-ignore comments to @ts-expect-error for better TypeScript practices (new lint rule) * Removed unnecessary @ts-ignore comments in some mode files (ditto) * Used "none return" based arrow functions for some map stuff * Replaced a `map()` call that didn't return anything to a for() loop * Fixed up some cypress stuff, noting work for the future
This commit is contained in:
@@ -93,7 +93,7 @@ export function applyColours(
|
||||
): void {
|
||||
const scheme = schemes.find(scheme => scheme.name === schemeName) ?? schemes[0];
|
||||
const newDecorations: monaco.editor.IModelDeltaDecoration[] = Object.entries(colours).map(([line, index]) => {
|
||||
const realLineNumber = Number.parseInt(line) + 1;
|
||||
const realLineNumber = Number.parseInt(line, 10) + 1;
|
||||
return {
|
||||
range: new monaco.Range(realLineNumber, 1, realLineNumber, 1),
|
||||
options: {
|
||||
|
||||
@@ -421,12 +421,16 @@ export class Hub {
|
||||
if (container.tab.header.tabs.length === 1 && container.tab.header.closeButton) {
|
||||
container.tab.header.closeButton.element.show();
|
||||
}
|
||||
container.tab.header.tabs.forEach(tab => tab.closeElement.show());
|
||||
container.tab.header.tabs.forEach(tab => {
|
||||
tab.closeElement.show();
|
||||
});
|
||||
} else {
|
||||
if (container.tab.header.tabs.length === 1 && container.tab.header.closeButton) {
|
||||
container.tab.header.closeButton.element.hide();
|
||||
}
|
||||
container.tab.header.tabs.forEach(tab => tab.closeElement.hide());
|
||||
container.tab.header.tabs.forEach(tab => {
|
||||
tab.closeElement.hide();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ export class LineColouring {
|
||||
let colourIdx = 0;
|
||||
|
||||
for (const editorIdStr of _.keys(this.colouredSourceLinesByEditor)) {
|
||||
const editorId = Number.parseInt(editorIdStr);
|
||||
const editorId = Number.parseInt(editorIdStr, 10);
|
||||
|
||||
const lines = this.getUniqueLinesForEditor(editorId);
|
||||
for (const line of lines) {
|
||||
@@ -116,7 +116,7 @@ export class LineColouring {
|
||||
const editorIds = _.keys(this.linesAndColourByEditor);
|
||||
|
||||
for (const compilerIdStr of compilerIds) {
|
||||
const compilerId = Number.parseInt(compilerIdStr);
|
||||
const compilerId = Number.parseInt(compilerIdStr, 10);
|
||||
for (const editorId of _.keys(this.colouredSourceLinesByEditor)) {
|
||||
for (const info of this.colouredSourceLinesByEditor[editorId]) {
|
||||
if (info.compilerId === compilerId && info.colourIdx >= 0) {
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
import * as monaco from 'monaco-editor';
|
||||
|
||||
// @ts-ignore "Could not find a declaration file"
|
||||
import * as cpp from 'monaco-editor/esm/vs/basic-languages/cpp/cpp';
|
||||
|
||||
function definition(): monaco.languages.IMonarchLanguage {
|
||||
|
||||
@@ -26,7 +26,6 @@ import $ from 'jquery';
|
||||
|
||||
import * as monaco from 'monaco-editor';
|
||||
|
||||
// @ts-ignore "Could not find a declaration file"
|
||||
import * as cpp from 'monaco-editor/esm/vs/basic-languages/cpp/cpp';
|
||||
|
||||
import cppp from './cppp-mode.js';
|
||||
|
||||
@@ -26,7 +26,6 @@ import $ from 'jquery';
|
||||
|
||||
import * as monaco from 'monaco-editor';
|
||||
|
||||
// @ts-ignore "Could not find a declaration file"
|
||||
import * as cpp from 'monaco-editor/esm/vs/basic-languages/cpp/cpp';
|
||||
import cppp from './cppp-mode.js';
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import $ from 'jquery';
|
||||
|
||||
import * as monaco from 'monaco-editor';
|
||||
|
||||
// @ts-ignore "Could not find a declaration file"
|
||||
import * as cpp from 'monaco-editor/esm/vs/basic-languages/cpp/cpp';
|
||||
import cppp from './cppp-mode.js';
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import $ from 'jquery';
|
||||
|
||||
import * as monaco from 'monaco-editor';
|
||||
|
||||
// @ts-ignore "Could not find a declaration file"
|
||||
import * as cpp from 'monaco-editor/esm/vs/basic-languages/cpp/cpp';
|
||||
|
||||
// We need to create a new definition for cpp so we can remove invalid keywords
|
||||
|
||||
@@ -26,7 +26,6 @@ import $ from 'jquery';
|
||||
|
||||
import * as monaco from 'monaco-editor';
|
||||
|
||||
// @ts-ignore "Could not find a declaration file"
|
||||
import * as cpp from 'monaco-editor/esm/vs/basic-languages/cpp/cpp';
|
||||
import cppp from './cppp-mode.js';
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import $ from 'jquery';
|
||||
|
||||
import * as monaco from 'monaco-editor';
|
||||
|
||||
// @ts-ignore "Could not find a declaration file"
|
||||
import * as cpp from 'monaco-editor/esm/vs/basic-languages/cpp/cpp';
|
||||
import cppp from './cppp-mode.js';
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import $ from 'jquery';
|
||||
|
||||
import * as monaco from 'monaco-editor';
|
||||
|
||||
// @ts-ignore "Could not find a declaration file"
|
||||
import * as cpp from 'monaco-editor/esm/vs/basic-languages/cpp/cpp';
|
||||
|
||||
function definition(): monaco.languages.IMonarchLanguage {
|
||||
|
||||
@@ -26,7 +26,6 @@ import $ from 'jquery';
|
||||
|
||||
import * as monaco from 'monaco-editor';
|
||||
|
||||
// @ts-ignore "Could not find a declaration file"
|
||||
import * as cpp from 'monaco-editor/esm/vs/basic-languages/cpp/cpp';
|
||||
|
||||
function definition(): monaco.languages.IMonarchLanguage {
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
import * as monaco from 'monaco-editor';
|
||||
|
||||
// @ts-ignore "Could not find a declaration file"
|
||||
import * as swift from 'monaco-editor/esm/vs/basic-languages/swift/swift';
|
||||
|
||||
function definition(): monaco.languages.IMonarchLanguage {
|
||||
|
||||
@@ -26,7 +26,6 @@ import $ from 'jquery';
|
||||
|
||||
import * as monaco from 'monaco-editor';
|
||||
|
||||
// @ts-ignore "Could not find a declaration file"
|
||||
import * as cpp from 'monaco-editor/esm/vs/basic-languages/cpp/cpp';
|
||||
|
||||
function definition(): monaco.languages.IMonarchLanguage {
|
||||
|
||||
@@ -26,7 +26,6 @@ import $ from 'jquery';
|
||||
|
||||
import * as monaco from 'monaco-editor';
|
||||
|
||||
// @ts-ignore "Could not find a declaration file"
|
||||
import * as cpp from 'monaco-editor/esm/vs/basic-languages/cpp/cpp';
|
||||
|
||||
// We need to ensure we use proper keywords for the Monaco Editor matcher. Note how
|
||||
|
||||
@@ -26,7 +26,6 @@ import $ from 'jquery';
|
||||
|
||||
import * as monaco from 'monaco-editor';
|
||||
|
||||
// @ts-ignore "Could not find a declaration file"
|
||||
import * as cpp from 'monaco-editor/esm/vs/basic-languages/cpp/cpp';
|
||||
|
||||
import nc from './nc-mode.js';
|
||||
|
||||
@@ -26,7 +26,6 @@ import $ from 'jquery';
|
||||
|
||||
import * as monaco from 'monaco-editor';
|
||||
|
||||
// @ts-ignore "Could not find a declaration file"
|
||||
import * as rust from 'monaco-editor/esm/vs/basic-languages/rust/rust';
|
||||
|
||||
// We need to patch the existing rust definition to fix hexadecimal literal highlighting
|
||||
|
||||
@@ -26,7 +26,6 @@ import $ from 'jquery';
|
||||
|
||||
import * as monaco from 'monaco-editor';
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore "Could not find a declaration file"
|
||||
import * as cpp from 'monaco-editor/esm/vs/basic-languages/cpp/cpp';
|
||||
|
||||
function definition(): monaco.languages.IMonarchLanguage {
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import JSZip from 'jszip';
|
||||
// @ts-ignore
|
||||
import path from 'path-browserify';
|
||||
import _ from 'underscore';
|
||||
import {FiledataPair} from '../types/compilation/compilation.interfaces.js';
|
||||
|
||||
@@ -649,7 +649,7 @@ export class Cfg extends Pane<CfgState> {
|
||||
const left = span_box.left - block_bounding_box.left;
|
||||
doc += `<text ${attrs({
|
||||
x: block.coordinates.x + left,
|
||||
y: block.coordinates.y + top + span_box.height / 2 + Number.parseInt(block_style.paddingTop),
|
||||
y: block.coordinates.y + top + span_box.height / 2 + Number.parseInt(block_style.paddingTop, 10),
|
||||
class: 'code',
|
||||
fill: span_style.color,
|
||||
})}>${escapeHTML(text)}</text>`;
|
||||
|
||||
@@ -489,38 +489,37 @@ export class Conformance extends Pane<ConformanceViewState> {
|
||||
|
||||
let libraries: Record<string, Library | false> = {};
|
||||
let first = true;
|
||||
compilers.map(compiler => {
|
||||
if (compiler) {
|
||||
const filteredLibraries = LibUtils.getSupportedLibraries(compiler.libsArr, langId, compiler.remote);
|
||||
for (const compiler of compilers) {
|
||||
if (!compiler) continue;
|
||||
const filteredLibraries = LibUtils.getSupportedLibraries(compiler.libsArr, langId, compiler.remote);
|
||||
|
||||
if (first) {
|
||||
libraries = _.extend({}, filteredLibraries);
|
||||
first = false;
|
||||
} else {
|
||||
const libsInCommon = _.intersection(_.keys(libraries), _.keys(filteredLibraries));
|
||||
if (first) {
|
||||
libraries = _.extend({}, filteredLibraries);
|
||||
first = false;
|
||||
} else {
|
||||
const libsInCommon = _.intersection(_.keys(libraries), _.keys(filteredLibraries));
|
||||
|
||||
for (const libKey in libraries) {
|
||||
const lib = libraries[libKey];
|
||||
if (lib && libsInCommon.includes(libKey)) {
|
||||
const versionsInCommon = _.intersection(
|
||||
Object.keys(lib.versions),
|
||||
Object.keys(filteredLibraries[libKey].versions),
|
||||
);
|
||||
for (const libKey in libraries) {
|
||||
const lib = libraries[libKey];
|
||||
if (lib && libsInCommon.includes(libKey)) {
|
||||
const versionsInCommon = _.intersection(
|
||||
Object.keys(lib.versions),
|
||||
Object.keys(filteredLibraries[libKey].versions),
|
||||
);
|
||||
|
||||
lib.versions = _.pick(lib.versions, (version, versionkey) => {
|
||||
return versionsInCommon.includes(versionkey);
|
||||
}) as Record<string, LibraryVersion>; // TODO(jeremy-rifkin)
|
||||
} else {
|
||||
libraries[libKey] = false;
|
||||
}
|
||||
lib.versions = _.pick(lib.versions, (version, versionkey) => {
|
||||
return versionsInCommon.includes(versionkey);
|
||||
}) as Record<string, LibraryVersion>; // TODO(jeremy-rifkin)
|
||||
} else {
|
||||
libraries[libKey] = false;
|
||||
}
|
||||
|
||||
libraries = _.omit(libraries, lib => {
|
||||
return !lib || _.isEmpty(lib.versions);
|
||||
}) as Record<string, Library>; // TODO(jeremy-rifkin)
|
||||
}
|
||||
|
||||
libraries = _.omit(libraries, lib => {
|
||||
return !lib || _.isEmpty(lib.versions);
|
||||
}) as Record<string, Library>; // TODO(jeremy-rifkin)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return libraries as CompilerLibs; // TODO(jeremy-rifkin)
|
||||
}
|
||||
|
||||
@@ -50,12 +50,12 @@ function decodeSelectizeValue(value: string): DiffTypeAndExtra {
|
||||
const opts = value.split(':');
|
||||
if (opts.length > 1) {
|
||||
return {
|
||||
difftype: Number.parseInt(opts[0]),
|
||||
difftype: Number.parseInt(opts[0], 10),
|
||||
extraoption: opts[1],
|
||||
};
|
||||
}
|
||||
return {
|
||||
difftype: Number.parseInt(value),
|
||||
difftype: Number.parseInt(value, 10),
|
||||
extraoption: '',
|
||||
};
|
||||
}
|
||||
@@ -432,7 +432,7 @@ export class Diff extends MonacoPane<monaco.editor.IStandaloneDiffEditor, DiffSt
|
||||
if (typeof id === 'string') {
|
||||
const p = id.indexOf('_exec');
|
||||
if (p !== -1) {
|
||||
const execId = Number.parseInt(id.substr(0, p));
|
||||
const execId = Number.parseInt(id.substr(0, p), 10);
|
||||
this.eventHub.emit('resendExecution', execId);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -26,7 +26,6 @@ import {Buffer} from 'buffer';
|
||||
import $ from 'jquery';
|
||||
import * as monaco from 'monaco-editor';
|
||||
import {editor} from 'monaco-editor';
|
||||
// @ts-ignore
|
||||
import * as monacoVim from 'monaco-vim';
|
||||
import TomSelect from 'tom-select';
|
||||
import _ from 'underscore';
|
||||
@@ -720,7 +719,7 @@ export class Editor extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Edit
|
||||
const states: any[] = [];
|
||||
|
||||
for (const compilerIdStr of Object.keys(this.ourCompilers)) {
|
||||
const compilerId = Number.parseInt(compilerIdStr);
|
||||
const compilerId = Number.parseInt(compilerIdStr, 10);
|
||||
|
||||
const glCompiler: Compiler | undefined = _.find(
|
||||
this.container.layoutManager.root.getComponentsByName('compiler'),
|
||||
@@ -1242,7 +1241,7 @@ export class Editor extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Edit
|
||||
// enabled: this.settings.colouriseBrackets,
|
||||
// independentColorPoolPerBracketType: true,
|
||||
// },
|
||||
// @ts-ignore once the bug is fixed we can remove this suppression
|
||||
// @ts-expect-error once the bug is fixed we can remove this suppression
|
||||
'bracketPairColorization.enabled': this.settings.colouriseBrackets,
|
||||
useVim: this.settings.useVim,
|
||||
quickSuggestions: this.settings.showQuickSuggestions,
|
||||
@@ -1469,17 +1468,17 @@ export class Editor extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Edit
|
||||
const editorModel = this.editor.getModel();
|
||||
const widgets = _.compact(
|
||||
output.map(obj => {
|
||||
if (!obj.tag) return;
|
||||
if (!obj.tag) return undefined;
|
||||
|
||||
const trees = this.hub.trees;
|
||||
if (trees && trees.length > 0) {
|
||||
if (obj.tag.file) {
|
||||
if (this.id !== trees[0].multifileService.getEditorIdByFilename(obj.tag.file)) {
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
} else {
|
||||
if (this.id !== trees[0].multifileService.getMainSourceEditorId()) {
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,7 +413,7 @@ export class OptPipeline extends MonacoPane<monaco.editor.IStandaloneDiffEditor,
|
||||
const target = e.target;
|
||||
this.passesList.find('.active').removeClass('active');
|
||||
$(target).addClass('active');
|
||||
this.displayPass(Number.parseInt(unwrap(target.getAttribute('data-i'))));
|
||||
this.displayPass(Number.parseInt(unwrap(target.getAttribute('data-i')), 10));
|
||||
});
|
||||
// try to select a pass
|
||||
if (this.state.selectedIndex >= passes.length) {
|
||||
@@ -484,7 +484,7 @@ export class OptPipeline extends MonacoPane<monaco.editor.IStandaloneDiffEditor,
|
||||
scrollMode: 'if-needed',
|
||||
block: 'nearest',
|
||||
});
|
||||
this.displayPass(Number.parseInt(unwrap(prev.getAttribute('data-i'))));
|
||||
this.displayPass(Number.parseInt(unwrap(prev.getAttribute('data-i')), 10));
|
||||
}
|
||||
}
|
||||
if (e.key === 'ArrowDown') {
|
||||
@@ -498,7 +498,7 @@ export class OptPipeline extends MonacoPane<monaco.editor.IStandaloneDiffEditor,
|
||||
scrollMode: 'if-needed',
|
||||
block: 'nearest',
|
||||
});
|
||||
this.displayPass(Number.parseInt(unwrap(next.getAttribute('data-i'))));
|
||||
this.displayPass(Number.parseInt(unwrap(next.getAttribute('data-i')), 10));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +170,9 @@ export class Opt extends MonacoPane<monaco.editor.IStandaloneCodeEditor, OptStat
|
||||
|
||||
this.editor?.changeViewZones(accessor => {
|
||||
const maxWidth = width ?? this.editor.getLayoutInfo().contentWidth;
|
||||
this.optRemarkViewZoneIds.forEach(id => accessor.removeZone(id));
|
||||
this.optRemarkViewZoneIds.forEach(id => {
|
||||
accessor.removeZone(id);
|
||||
});
|
||||
this.optRemarkViewZoneIds = remarksToDisplay.map(({displayString, optType, DebugLoc}) => {
|
||||
const domNode = document.createElement('div');
|
||||
domNode.classList.add('view-line', 'opt-line', optType.toLowerCase());
|
||||
|
||||
@@ -271,7 +271,7 @@ export class Tree {
|
||||
|
||||
private sendChangesToAllEditors() {
|
||||
for (const compilerId in this.ourCompilers) {
|
||||
this.sendCompilerChangesToEditor(Number.parseInt(compilerId));
|
||||
this.sendCompilerChangesToEditor(Number.parseInt(compilerId, 10));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -653,7 +653,7 @@ export class Tree {
|
||||
this.lineColouring.clear();
|
||||
|
||||
for (const [compilerId, asm] of Object.entries(this.asmByCompiler)) {
|
||||
this.lineColouring.addFromAssembly(Number.parseInt(compilerId), asm);
|
||||
this.lineColouring.addFromAssembly(Number.parseInt(compilerId, 10), asm);
|
||||
}
|
||||
|
||||
this.lineColouring.calculate();
|
||||
@@ -663,7 +663,7 @@ export class Tree {
|
||||
|
||||
private updateColours() {
|
||||
for (const compilerId in this.ourCompilers) {
|
||||
const id: number = Number.parseInt(compilerId);
|
||||
const id: number = Number.parseInt(compilerId, 10);
|
||||
this.eventHub.emit(
|
||||
'coloursForCompiler',
|
||||
id,
|
||||
@@ -684,7 +684,7 @@ export class Tree {
|
||||
|
||||
private updateColoursNone() {
|
||||
for (const compilerId in this.ourCompilers) {
|
||||
this.eventHub.emit('coloursForCompiler', Number.parseInt(compilerId), {}, this.settings.colourScheme);
|
||||
this.eventHub.emit('coloursForCompiler', Number.parseInt(compilerId, 10), {}, this.settings.colourScheme);
|
||||
}
|
||||
|
||||
this.multifileService.forEachOpenFile((file: MultifileFile) => {
|
||||
|
||||
@@ -27,7 +27,7 @@ import {localStorage} from './local.js';
|
||||
const CURRENT_SLIDE_KEY = 'presentationCurrentSlide';
|
||||
|
||||
export class Presentation {
|
||||
public currentSlide = Number.parseInt(localStorage.get(CURRENT_SLIDE_KEY, '0'));
|
||||
public currentSlide = Number.parseInt(localStorage.get(CURRENT_SLIDE_KEY, '0'), 10);
|
||||
public originalLocation = window.location.href;
|
||||
|
||||
public constructor(public maxSlides: number) {}
|
||||
|
||||
@@ -131,7 +131,9 @@ class Encoders {
|
||||
if (b) {
|
||||
a[a.length] = ',';
|
||||
}
|
||||
k = Number.isNaN(Number.parseInt(i)) ? Encoders.string(i) : Encoders.number(Number.parseInt(i));
|
||||
k = Number.isNaN(Number.parseInt(i, 10))
|
||||
? Encoders.string(i)
|
||||
: Encoders.number(Number.parseInt(i, 10));
|
||||
a.push(k, ':', v);
|
||||
b = true;
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ class Slider extends BaseSetting {
|
||||
}
|
||||
|
||||
override getUi(): number {
|
||||
return Number.parseInt(this.val()?.toString() ?? '0');
|
||||
return Number.parseInt(this.val()?.toString() ?? '0', 10);
|
||||
}
|
||||
|
||||
private updateDisplay() {
|
||||
@@ -189,7 +189,7 @@ class Numeric extends BaseSetting {
|
||||
}
|
||||
|
||||
override getUi(): number {
|
||||
return this.clampValue(Number.parseInt(this.val()?.toString() ?? '0'));
|
||||
return this.clampValue(Number.parseInt(this.val()?.toString() ?? '0', 10));
|
||||
}
|
||||
|
||||
override putUi(value: number) {
|
||||
@@ -377,7 +377,7 @@ export class Settings {
|
||||
).elem;
|
||||
defaultFontScaleSelector.on('change', e => {
|
||||
assert(e.target instanceof HTMLSelectElement);
|
||||
this.eventHub.emit('broadcastFontScale', Number.parseInt(e.target.value));
|
||||
this.eventHub.emit('broadcastFontScale', Number.parseInt(e.target.value, 10));
|
||||
});
|
||||
|
||||
const formats: FormatBase[] = ['Google', 'LLVM', 'Mozilla', 'Chromium', 'WebKit', 'Microsoft', 'GNU'];
|
||||
|
||||
@@ -111,9 +111,9 @@ export class Sharing {
|
||||
this.shareFull = $('#shareFull');
|
||||
this.shareEmbed = $('#shareEmbed');
|
||||
|
||||
[this.shareShort, this.shareFull, this.shareEmbed].forEach(el =>
|
||||
el.on('click', e => BootstrapUtils.showModal(this.shareLinkDialog, e.currentTarget)),
|
||||
);
|
||||
[this.shareShort, this.shareFull, this.shareEmbed].forEach(el => {
|
||||
el.on('click', e => BootstrapUtils.showModal(this.shareLinkDialog, e.currentTarget));
|
||||
});
|
||||
this.settings = Settings.getStoredSettings();
|
||||
|
||||
this.clippyButton = null;
|
||||
@@ -477,7 +477,9 @@ export class Sharing {
|
||||
if (component.componentState) {
|
||||
Object.keys(component.componentState)
|
||||
.filter(e => keysToRemove.includes(e))
|
||||
.forEach(key => delete component.componentState[key]);
|
||||
.forEach(key => {
|
||||
delete component.componentState[key];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user