Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6aebe26cc9 | ||
|
|
f93794717e | ||
|
|
0ebf482936 | ||
|
|
b5b8083acd | ||
|
|
219658761f |
12
NEWS.md
12
NEWS.md
@@ -1,5 +1,16 @@
|
||||
# Changelog
|
||||
|
||||
## 2.32.0
|
||||
|
||||
Released 2016-04-06
|
||||
|
||||
New features:
|
||||
- Added support for dynamic styling for widgets in named maps
|
||||
|
||||
Announcements:
|
||||
- Upgrades windshaft to [1.17.0](https://github.com/CartoDB/Windshaft/releases/tag/1.17.0)
|
||||
|
||||
|
||||
## 2.31.2
|
||||
|
||||
Released 2016-04-04
|
||||
@@ -8,6 +19,7 @@ Bug fixes:
|
||||
- Overviews integration for named layers #400
|
||||
- Support wrapped queries in named layers #405
|
||||
|
||||
|
||||
## 2.31.1
|
||||
|
||||
Released 2016-03-23
|
||||
|
||||
@@ -477,7 +477,11 @@ o.instance = function(template, params) {
|
||||
var layergroup = JSON.parse(JSON.stringify(template.layergroup));
|
||||
for (var i=0; i<layergroup.layers.length; ++i) {
|
||||
var lyropt = layergroup.layers[i].options;
|
||||
if ( lyropt.cartocss ) {
|
||||
|
||||
if ( params.styles && params.styles[i] ) {
|
||||
// dynamic styling for this layer
|
||||
lyropt.cartocss = params.styles[i];
|
||||
} else if ( lyropt.cartocss ) {
|
||||
lyropt.cartocss = _replaceVars(lyropt.cartocss, all_params);
|
||||
}
|
||||
if ( lyropt.sql) {
|
||||
|
||||
123
npm-shrinkwrap.json
generated
123
npm-shrinkwrap.json
generated
@@ -90,7 +90,7 @@
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.10",
|
||||
"from": "mime-types@>=2.1.2 <2.2.0",
|
||||
"from": "mime-types@>=2.1.10 <2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.10.tgz",
|
||||
"dependencies": {
|
||||
"mime-db": {
|
||||
@@ -203,7 +203,7 @@
|
||||
"dependencies": {
|
||||
"mime-types": {
|
||||
"version": "2.1.10",
|
||||
"from": "mime-types@>=2.1.6 <2.2.0",
|
||||
"from": "mime-types@>=2.1.10 <2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.10.tgz",
|
||||
"dependencies": {
|
||||
"mime-db": {
|
||||
@@ -267,7 +267,7 @@
|
||||
"dependencies": {
|
||||
"unpipe": {
|
||||
"version": "1.0.0",
|
||||
"from": "unpipe@1.0.0",
|
||||
"from": "unpipe@>=1.0.0 <1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
|
||||
}
|
||||
}
|
||||
@@ -382,7 +382,7 @@
|
||||
},
|
||||
"type-is": {
|
||||
"version": "1.6.12",
|
||||
"from": "type-is@>=1.6.10 <1.7.0",
|
||||
"from": "type-is@>=1.6.6 <1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.12.tgz",
|
||||
"dependencies": {
|
||||
"media-typer": {
|
||||
@@ -392,7 +392,7 @@
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.10",
|
||||
"from": "mime-types@>=2.1.6 <2.2.0",
|
||||
"from": "mime-types@>=2.1.10 <2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.10.tgz",
|
||||
"dependencies": {
|
||||
"mime-db": {
|
||||
@@ -453,7 +453,7 @@
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.1",
|
||||
"from": "inherits@>=2.0.0 <3.0.0",
|
||||
"from": "inherits@>=2.0.1 <2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
|
||||
}
|
||||
}
|
||||
@@ -595,7 +595,7 @@
|
||||
"dependencies": {
|
||||
"async": {
|
||||
"version": "1.5.2",
|
||||
"from": "async@>=1.0.0 <2.0.0",
|
||||
"from": "async@>=1.5.2 <2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz"
|
||||
}
|
||||
}
|
||||
@@ -729,21 +729,14 @@
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.10.2.tgz"
|
||||
},
|
||||
"chalk": {
|
||||
"version": "1.1.1",
|
||||
"version": "1.1.3",
|
||||
"from": "chalk@>=1.0.0 <2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "2.2.0",
|
||||
"from": "ansi-styles@>=2.1.0 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.0.tgz",
|
||||
"dependencies": {
|
||||
"color-convert": {
|
||||
"version": "1.0.0",
|
||||
"from": "color-convert@>=1.0.0 <2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.0.0.tgz"
|
||||
}
|
||||
}
|
||||
"version": "2.2.1",
|
||||
"from": "ansi-styles@>=2.2.1 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz"
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
@@ -964,9 +957,9 @@
|
||||
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz"
|
||||
},
|
||||
"request": {
|
||||
"version": "2.69.0",
|
||||
"version": "2.70.0",
|
||||
"from": "request@>=2.67.0 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.69.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.70.0.tgz",
|
||||
"dependencies": {
|
||||
"aws-sign2": {
|
||||
"version": "0.6.0",
|
||||
@@ -998,9 +991,9 @@
|
||||
}
|
||||
},
|
||||
"bl": {
|
||||
"version": "1.0.3",
|
||||
"from": "bl@>=1.0.0 <1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-1.0.3.tgz",
|
||||
"version": "1.1.2",
|
||||
"from": "bl@>=1.1.2 <1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz",
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "2.0.6",
|
||||
@@ -1086,21 +1079,14 @@
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz",
|
||||
"dependencies": {
|
||||
"chalk": {
|
||||
"version": "1.1.1",
|
||||
"version": "1.1.3",
|
||||
"from": "chalk@>=1.1.1 <2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "2.2.0",
|
||||
"from": "ansi-styles@>=2.1.0 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.0.tgz",
|
||||
"dependencies": {
|
||||
"color-convert": {
|
||||
"version": "1.0.0",
|
||||
"from": "color-convert@>=1.0.0 <2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.0.0.tgz"
|
||||
}
|
||||
}
|
||||
"version": "2.2.1",
|
||||
"from": "ansi-styles@>=2.2.1 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz"
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
@@ -1200,7 +1186,7 @@
|
||||
},
|
||||
"hawk": {
|
||||
"version": "3.1.3",
|
||||
"from": "hawk@>=3.1.0 <3.2.0",
|
||||
"from": "hawk@>=3.1.3 <3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
|
||||
"dependencies": {
|
||||
"hoek": {
|
||||
@@ -1285,9 +1271,9 @@
|
||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz"
|
||||
},
|
||||
"tweetnacl": {
|
||||
"version": "0.14.1",
|
||||
"version": "0.14.3",
|
||||
"from": "tweetnacl@>=0.13.0 <1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.1.tgz"
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.3.tgz"
|
||||
},
|
||||
"jodid25519": {
|
||||
"version": "1.0.2",
|
||||
@@ -1337,13 +1323,13 @@
|
||||
},
|
||||
"oauth-sign": {
|
||||
"version": "0.8.1",
|
||||
"from": "oauth-sign@>=0.8.0 <0.9.0",
|
||||
"from": "oauth-sign@>=0.8.1 <0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.1.tgz"
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.0.2",
|
||||
"from": "qs@>=6.0.2 <6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.0.2.tgz"
|
||||
"version": "6.1.0",
|
||||
"from": "qs@>=6.1.0 <6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.1.0.tgz"
|
||||
},
|
||||
"stringstream": {
|
||||
"version": "0.0.5",
|
||||
@@ -1370,9 +1356,9 @@
|
||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz"
|
||||
},
|
||||
"windshaft": {
|
||||
"version": "1.16.1",
|
||||
"from": "windshaft@1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/windshaft/-/windshaft-1.16.1.tgz",
|
||||
"version": "1.17.0",
|
||||
"from": "windshaft@1.17.0",
|
||||
"resolved": "https://registry.npmjs.org/windshaft/-/windshaft-1.17.0.tgz",
|
||||
"dependencies": {
|
||||
"abaculus": {
|
||||
"version": "1.1.0-cdb4",
|
||||
@@ -3033,18 +3019,18 @@
|
||||
}
|
||||
},
|
||||
"sqlite3": {
|
||||
"version": "3.1.2",
|
||||
"version": "3.1.3",
|
||||
"from": "sqlite3@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-3.1.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-3.1.3.tgz",
|
||||
"dependencies": {
|
||||
"nan": {
|
||||
"version": "2.2.0",
|
||||
"version": "2.2.1",
|
||||
"from": "nan@>=2.2.0 <2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.2.0.tgz"
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.2.1.tgz"
|
||||
},
|
||||
"node-pre-gyp": {
|
||||
"version": "0.6.24",
|
||||
"from": "node-pre-gyp@~0.6.18",
|
||||
"version": "0.6.25",
|
||||
"from": "node-pre-gyp@~0.6.25",
|
||||
"dependencies": {
|
||||
"nopt": {
|
||||
"version": "3.0.6",
|
||||
@@ -3080,7 +3066,7 @@
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.0.6",
|
||||
"from": "readable-stream@~2.0.5",
|
||||
"from": "readable-stream@^2.0.0 || ^1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
|
||||
"dependencies": {
|
||||
"core-util-is": {
|
||||
@@ -3198,9 +3184,9 @@
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.3.2.tgz",
|
||||
"dependencies": {
|
||||
"lru-cache": {
|
||||
"version": "4.0.0",
|
||||
"version": "4.0.1",
|
||||
"from": "lru-cache@^4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.1.tgz",
|
||||
"dependencies": {
|
||||
"pseudomap": {
|
||||
"version": "1.0.2",
|
||||
@@ -3305,21 +3291,14 @@
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz",
|
||||
"dependencies": {
|
||||
"chalk": {
|
||||
"version": "1.1.1",
|
||||
"version": "1.1.3",
|
||||
"from": "chalk@^1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "2.2.0",
|
||||
"from": "ansi-styles@^2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.0.tgz",
|
||||
"dependencies": {
|
||||
"color-convert": {
|
||||
"version": "1.0.0",
|
||||
"from": "color-convert@^1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.0.0.tgz"
|
||||
}
|
||||
}
|
||||
"version": "2.2.1",
|
||||
"from": "ansi-styles@^2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz"
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
@@ -3504,9 +3483,9 @@
|
||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz"
|
||||
},
|
||||
"tweetnacl": {
|
||||
"version": "0.14.1",
|
||||
"version": "0.14.3",
|
||||
"from": "tweetnacl@>=0.13.0 <1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.1.tgz"
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.3.tgz"
|
||||
},
|
||||
"jodid25519": {
|
||||
"version": "1.0.2",
|
||||
@@ -3634,7 +3613,7 @@
|
||||
},
|
||||
"fstream": {
|
||||
"version": "1.0.8",
|
||||
"from": "fstream@^1.0.2",
|
||||
"from": "fstream@~1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.8.tgz",
|
||||
"dependencies": {
|
||||
"graceful-fs": {
|
||||
@@ -3644,7 +3623,7 @@
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.1",
|
||||
"from": "inherits@~2.0.1",
|
||||
"from": "inherits@~2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
|
||||
}
|
||||
}
|
||||
@@ -3687,7 +3666,7 @@
|
||||
},
|
||||
"once": {
|
||||
"version": "1.3.3",
|
||||
"from": "once@^1.3.0",
|
||||
"from": "once@~1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz",
|
||||
"dependencies": {
|
||||
"wrappy": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "windshaft-cartodb",
|
||||
"version": "2.31.2",
|
||||
"version": "2.32.0",
|
||||
"description": "A map tile server for CartoDB",
|
||||
"keywords": [
|
||||
"cartodb"
|
||||
@@ -26,7 +26,7 @@
|
||||
"node-statsd": "~0.0.7",
|
||||
"underscore" : "~1.6.0",
|
||||
"dot": "~1.0.2",
|
||||
"windshaft": "1.16.1",
|
||||
"windshaft": "1.17.0",
|
||||
"step": "~0.0.6",
|
||||
"queue-async": "~1.0.7",
|
||||
"request": "~2.62.0",
|
||||
|
||||
169
test/acceptance/dynamic-styling-named-maps.js
Normal file
169
test/acceptance/dynamic-styling-named-maps.js
Normal file
@@ -0,0 +1,169 @@
|
||||
var assert = require('../support/assert');
|
||||
var step = require('step');
|
||||
var LayergroupToken = require('../../lib/cartodb/models/layergroup_token');
|
||||
var testHelper = require(__dirname + '/../support/test_helper');
|
||||
var CartodbWindshaft = require(__dirname + '/../../lib/cartodb/server');
|
||||
var serverOptions = require(__dirname + '/../../lib/cartodb/server_options');
|
||||
var server = new CartodbWindshaft(serverOptions);
|
||||
|
||||
describe('dynamic styling for named maps', function() {
|
||||
|
||||
var keysToDelete;
|
||||
|
||||
beforeEach(function() {
|
||||
keysToDelete = {};
|
||||
});
|
||||
|
||||
afterEach(function(done) {
|
||||
testHelper.deleteRedisKeys(keysToDelete, done);
|
||||
});
|
||||
|
||||
var templateId = 'dynamic-styling-template-1';
|
||||
|
||||
var template = {
|
||||
version: '0.0.1',
|
||||
name: templateId,
|
||||
auth: { method: 'open' },
|
||||
placeholders: {
|
||||
color: {
|
||||
type: "css_color",
|
||||
default: "Reds"
|
||||
}
|
||||
},
|
||||
layergroup: {
|
||||
version: '1.0.0',
|
||||
layers: [{
|
||||
options: {
|
||||
sql: 'SELECT * FROM test_table',
|
||||
cartocss: [
|
||||
'#layer {',
|
||||
' marker-fill: #000;',
|
||||
'}'
|
||||
].join('\n'),
|
||||
cartocss_version: '2.0.2'
|
||||
}
|
||||
}, {
|
||||
options: {
|
||||
sql: 'SELECT * FROM test_table',
|
||||
cartocss: [
|
||||
'#layer {',
|
||||
' marker-fill: #000;',
|
||||
'}'
|
||||
].join('\n'),
|
||||
cartocss_version: '2.0.2'
|
||||
}
|
||||
}, {
|
||||
options: {
|
||||
sql: 'SELECT * FROM test_table',
|
||||
cartocss: [
|
||||
'#layer {',
|
||||
' marker-fill: #000;',
|
||||
'}'
|
||||
].join('\n'),
|
||||
cartocss_version: '2.0.2'
|
||||
}
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
var templateParams = {
|
||||
styles: {
|
||||
0: [
|
||||
'#layer {',
|
||||
' marker-fill: #fabada;',
|
||||
'}'
|
||||
].join('\n'),
|
||||
2: [
|
||||
'#layer {',
|
||||
' marker-fill: #cebada;',
|
||||
'}'
|
||||
].join('\n')
|
||||
}
|
||||
};
|
||||
|
||||
it('should instantiate a template applying cartocss dynamicly', function (done) {
|
||||
step(
|
||||
function postTemplate() {
|
||||
var next = this;
|
||||
|
||||
assert.response(server, {
|
||||
url: '/api/v1/map/named?api_key=1234',
|
||||
method: 'POST',
|
||||
headers: { host: 'localhost', 'Content-Type': 'application/json' },
|
||||
data: JSON.stringify(template)
|
||||
}, {},
|
||||
function (res, err) {
|
||||
next(err, res);
|
||||
});
|
||||
},
|
||||
function checkTemplate(err, res) {
|
||||
assert.ifError(err);
|
||||
assert.equal(res.statusCode, 200);
|
||||
assert.deepEqual(JSON.parse(res.body), {
|
||||
template_id: templateId
|
||||
});
|
||||
|
||||
return null;
|
||||
},
|
||||
function instantiateTemplate(err) {
|
||||
assert.ifError(err);
|
||||
|
||||
var next = this;
|
||||
assert.response(server, {
|
||||
url: '/api/v1/map/named/' + templateId,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
host: 'localhost',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: JSON.stringify(templateParams)
|
||||
}, {},
|
||||
function (res, err) {
|
||||
return next(err, res);
|
||||
});
|
||||
},
|
||||
function checkInstanciation(err, res) {
|
||||
assert.ifError(err);
|
||||
|
||||
assert.equal(res.statusCode, 200);
|
||||
|
||||
var parsedBody = JSON.parse(res.body);
|
||||
|
||||
keysToDelete['map_cfg|' + LayergroupToken.parse(parsedBody.layergroupid).token] = 0;
|
||||
keysToDelete['user:localhost:mapviews:global'] = 5;
|
||||
|
||||
assert.equal(parsedBody.metadata.layers[0].meta.cartocss, templateParams.styles['0']);
|
||||
assert.equal(
|
||||
parsedBody.metadata.layers[1].meta.cartocss,
|
||||
template.layergroup.layers[1].options.cartocss
|
||||
);
|
||||
assert.equal(parsedBody.metadata.layers[2].meta.cartocss, templateParams.styles['2']);
|
||||
|
||||
return parsedBody.layergroupid;
|
||||
},
|
||||
function deleteTemplate(err) {
|
||||
assert.ifError(err);
|
||||
|
||||
var next = this;
|
||||
|
||||
assert.response(server, {
|
||||
url: '/api/v1/map/named/' + templateId + '?api_key=1234',
|
||||
method: 'DELETE',
|
||||
headers: { host: 'localhost' }
|
||||
}, {}, function (res, err) {
|
||||
next(err, res);
|
||||
});
|
||||
},
|
||||
function checkDeleteTemplate(err, res) {
|
||||
assert.ifError(err);
|
||||
assert.equal(res.statusCode, 204);
|
||||
assert.ok(!res.body);
|
||||
|
||||
return null;
|
||||
},
|
||||
function finish(err) {
|
||||
done(err);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user