Merge branch 'master' into develop
commit
672d7352bb
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"post-cache": "Кэш записи",
|
"post-cache": "Кэш записи",
|
||||||
"posts-in-cache": "Записей в кэше",
|
"posts-in-cache": "Записей в кэше",
|
||||||
"average-post-size": "Average Post Size",
|
"average-post-size": "Средний размер записи",
|
||||||
"length-to-max": "Length / Max",
|
"length-to-max": "Длина / Максимальная",
|
||||||
"percent-full": "%1% Full",
|
"percent-full": "%1% Full",
|
||||||
"post-cache-size": "Post Cache Size",
|
"post-cache-size": "Размер записи в кэше",
|
||||||
"items-in-cache": "Items in Cache",
|
"items-in-cache": "Items in Cache",
|
||||||
"control-panel": "Control Panel",
|
"control-panel": "Панель управления",
|
||||||
"update-settings": "Update Cache Settings"
|
"update-settings": "Обновить настройки кэша"
|
||||||
}
|
}
|
@ -1,90 +1,94 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
/* global app, define, socket, config */
|
/* global app, define, socket, config */
|
||||||
|
|
||||||
define('sounds', ['buzz'], function (buzz) {
|
define('sounds', function () {
|
||||||
var Sounds = {};
|
var Sounds = {};
|
||||||
|
|
||||||
var loadedSounds = {};
|
var fileMap;
|
||||||
var eventSoundMapping;
|
var soundMap;
|
||||||
var files;
|
var cache = {};
|
||||||
|
|
||||||
socket.on('event:sounds.reloadMapping', function () {
|
Sounds.loadMap = function loadMap(callback) {
|
||||||
Sounds.reloadMapping();
|
socket.emit('modules.sounds.getUserSoundMap', function (err, map) {
|
||||||
});
|
|
||||||
|
|
||||||
Sounds.reloadMapping = function () {
|
|
||||||
socket.emit('modules.sounds.getMapping', function (err, mapping) {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return app.alertError(err.message);
|
return app.alertError(err.message);
|
||||||
}
|
}
|
||||||
eventSoundMapping = mapping;
|
soundMap = map;
|
||||||
|
if (callback) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function loadData(callback) {
|
function loadData(callback) {
|
||||||
socket.emit('modules.sounds.getData', function (err, data) {
|
var outstanding = 2;
|
||||||
if (err) {
|
function after() {
|
||||||
return app.alertError('[sounds] Could not load sound mapping!');
|
outstanding -= 1;
|
||||||
}
|
if (outstanding === 0 && callback) {
|
||||||
eventSoundMapping = data.mapping;
|
callback();
|
||||||
files = data.files;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function isSoundLoaded(fileName) {
|
|
||||||
return loadedSounds[fileName];
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadFile(fileName, callback) {
|
|
||||||
function createSound() {
|
|
||||||
if (files && files[fileName]) {
|
|
||||||
loadedSounds[fileName] = new buzz.sound(files[fileName]);
|
|
||||||
}
|
}
|
||||||
callback();
|
|
||||||
}
|
}
|
||||||
|
if (fileMap) {
|
||||||
if (isSoundLoaded(fileName)) {
|
outstanding -= 1;
|
||||||
return callback();
|
} else {
|
||||||
|
$.getJSON(config.relative_path + '/assets/sounds/fileMap.json', function (map) {
|
||||||
|
fileMap = map;
|
||||||
|
after();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!files || !files[fileName]) {
|
Sounds.loadMap(after);
|
||||||
return loadData(createSound);
|
|
||||||
}
|
|
||||||
createSound();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Sounds.play = function (name) {
|
Sounds.playSound = function playSound(soundName) {
|
||||||
function play() {
|
if (!soundMap || !fileMap) {
|
||||||
Sounds.playFile(eventSoundMapping[name]);
|
return loadData(after);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!eventSoundMapping) {
|
function after() {
|
||||||
return loadData(play);
|
if (!fileMap[soundName]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var audio = cache[soundName] = cache[soundName] || new Audio(config.relative_path + '/assets/sounds/' + fileMap[soundName]);
|
||||||
|
audio.pause();
|
||||||
|
audio.currentTime = 0;
|
||||||
|
audio.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
play();
|
after();
|
||||||
};
|
};
|
||||||
|
|
||||||
Sounds.playFile = function (fileName) {
|
Sounds.play = function play(type, id) {
|
||||||
if (!fileName) {
|
function after() {
|
||||||
return;
|
if (!soundMap[type]) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
function play() {
|
|
||||||
if (loadedSounds[fileName]) {
|
if (id) {
|
||||||
loadedSounds[fileName].play();
|
var item = 'sounds.handled:' + id;
|
||||||
} else {
|
if (sessionStorage.getItem(item)) {
|
||||||
app.alertError('[sounds] Not found: ' + fileName);
|
return;
|
||||||
|
}
|
||||||
|
sessionStorage.setItem(item, true);
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
sessionStorage.removeItem(item);
|
||||||
|
}, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Sounds.playSound(soundMap[type]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSoundLoaded(fileName)) {
|
if (!soundMap || !fileMap) {
|
||||||
play();
|
return loadData(after);
|
||||||
} else {
|
|
||||||
loadFile(fileName, play);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
after();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
socket.on('event:sounds.reloadMapping', function () {
|
||||||
|
Sounds.loadMap();
|
||||||
|
});
|
||||||
|
|
||||||
return Sounds;
|
return Sounds;
|
||||||
});
|
});
|
||||||
|
@ -1,24 +1,46 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var meta = require('../../meta');
|
var plugins = require('../../plugins');
|
||||||
|
var db = require('../../database');
|
||||||
|
|
||||||
var soundsController = {};
|
var soundsController = {};
|
||||||
|
|
||||||
soundsController.get = function (req, res, next) {
|
soundsController.get = function (req, res, next) {
|
||||||
meta.sounds.getFiles(function (err, sounds) {
|
db.getObject('settings:sounds', function (err, settings) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
settings = settings || {};
|
||||||
|
|
||||||
sounds = Object.keys(sounds).map(function (name) {
|
var types = [
|
||||||
return {
|
'notification',
|
||||||
name: name
|
'chat-incoming',
|
||||||
};
|
'chat-outgoing',
|
||||||
});
|
];
|
||||||
|
var output = {};
|
||||||
|
|
||||||
|
types.forEach(function (type) {
|
||||||
|
var soundpacks = plugins.soundpacks.map(function (pack) {
|
||||||
|
var sounds = Object.keys(pack.sounds).map(function (soundName) {
|
||||||
|
var value = pack.name + ' | ' + soundName;
|
||||||
|
return {
|
||||||
|
name: soundName,
|
||||||
|
value: value,
|
||||||
|
selected: value === settings[type],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
res.render('admin/general/sounds', {
|
return {
|
||||||
sounds: sounds
|
name: pack.name,
|
||||||
|
sounds: sounds,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
output[type + '-sound'] = soundpacks;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
res.render('admin/general/sounds', output);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,109 +1,121 @@
|
|||||||
<div class="registration panel panel-primary">
|
<div class="row">
|
||||||
<div class="panel-heading">
|
<div class="col-xs-12">
|
||||||
[[admin/manage/registration:queue]]
|
<div class="registration panel panel-primary">
|
||||||
</div>
|
<div class="panel-heading">
|
||||||
<!-- IF !users.length -->
|
[[admin/manage/registration:queue]]
|
||||||
<p class="panel-body">
|
</div>
|
||||||
[[admin/manage/registration:description, {config.relative_path}/admin/settings/user]]
|
<!-- IF !users.length -->
|
||||||
</p>
|
<p class="panel-body">
|
||||||
<!-- ENDIF !users.length -->
|
[[admin/manage/registration:description, {config.relative_path}/admin/settings/user]]
|
||||||
<div class="table-responsive">
|
</p>
|
||||||
<table class="table table-striped users-list">
|
<!-- ENDIF !users.length -->
|
||||||
<tr>
|
<div class="table-responsive">
|
||||||
<th>[[admin/manage/registration:list.name]]</th>
|
<table class="table table-striped users-list">
|
||||||
<th>[[admin/manage/registration:list.email]]</th>
|
<thead>
|
||||||
<th class="hidden-xs">[[admin/manage/registration:list.ip]]</th>
|
<tr>
|
||||||
<th class="hidden-xs">[[admin/manage/registration:list.time]]</th>
|
<th>[[admin/manage/registration:list.name]]</th>
|
||||||
<!-- BEGIN customHeaders -->
|
<th>[[admin/manage/registration:list.email]]</th>
|
||||||
<th class="hidden-xs">{customHeaders.label}</th>
|
<th class="hidden-xs">[[admin/manage/registration:list.ip]]</th>
|
||||||
<!-- END customHeaders -->
|
<th class="hidden-xs">[[admin/manage/registration:list.time]]</th>
|
||||||
<th></th>
|
<!-- BEGIN customHeaders -->
|
||||||
</tr>
|
<th class="hidden-xs">{customHeaders.label}</th>
|
||||||
<!-- BEGIN users -->
|
<!-- END customHeaders -->
|
||||||
<tr data-username="{users.username}">
|
<th></th>
|
||||||
<td>
|
</tr>
|
||||||
<!-- IF users.usernameSpam -->
|
</thead>
|
||||||
<i class="fa fa-times-circle text-danger" title="[[admin/manage/registration:list.username-spam, {users.spamData.username.frequency}, {users.spamData.username.appears}, {users.spamData.username.confidence}]]"></i>
|
<tbody>
|
||||||
<!-- ELSE -->
|
<!-- BEGIN users -->
|
||||||
<i class="fa fa-check text-success"></i>
|
<tr data-username="{users.username}">
|
||||||
<!-- ENDIF users.usernameSpam -->
|
<td>
|
||||||
{users.username}
|
<!-- IF users.usernameSpam -->
|
||||||
</td>
|
<i class="fa fa-times-circle text-danger" title="[[admin/manage/registration:list.username-spam, {users.spamData.username.frequency}, {users.spamData.username.appears}, {users.spamData.username.confidence}]]"></i>
|
||||||
<td>
|
<!-- ELSE -->
|
||||||
<!-- IF users.emailSpam -->
|
<i class="fa fa-check text-success"></i>
|
||||||
<i class="fa fa-times-circle text-danger" title="[[admin/manage/registration:list.email-spam, {users.spamData.email.frequency}, {users.spamData.email.appears}]]"></i>
|
<!-- ENDIF users.usernameSpam -->
|
||||||
<!-- ELSE -->
|
{users.username}
|
||||||
<i class="fa fa-check text-success"></i>
|
</td>
|
||||||
<!-- ENDIF users.emailSpam -->
|
<td>
|
||||||
{users.email}
|
<!-- IF users.emailSpam -->
|
||||||
</td>
|
<i class="fa fa-times-circle text-danger" title="[[admin/manage/registration:list.email-spam, {users.spamData.email.frequency}, {users.spamData.email.appears}]]"></i>
|
||||||
<td class="hidden-xs">
|
<!-- ELSE -->
|
||||||
<!-- IF users.ipSpam -->
|
<i class="fa fa-check text-success"></i>
|
||||||
<i class="fa fa-times-circle text-danger" title="[[admin/manage/registration:list.ip-spam, {users.spamData.ip.frequency}, {users.spamData.ip.appears}]]"></i>
|
<!-- ENDIF users.emailSpam -->
|
||||||
<!-- ELSE -->
|
{users.email}
|
||||||
<i class="fa fa-check text-success"></i>
|
</td>
|
||||||
<!-- ENDIF users.ipSpam -->
|
<td class="hidden-xs">
|
||||||
{users.ip}
|
<!-- IF users.ipSpam -->
|
||||||
<!-- BEGIN users.ipMatch -->
|
<i class="fa fa-times-circle text-danger" title="[[admin/manage/registration:list.ip-spam, {users.spamData.ip.frequency}, {users.spamData.ip.appears}]]"></i>
|
||||||
<br>
|
<!-- ELSE -->
|
||||||
<!-- IF users.ipMatch.picture -->
|
<i class="fa fa-check text-success"></i>
|
||||||
<img src="{users.ipMatch.picture}" class="user-img"/>
|
<!-- ENDIF users.ipSpam -->
|
||||||
<!-- ELSE -->
|
{users.ip}
|
||||||
<div class="user-img avatar avatar-sm" style="background-color: {users.ipMatch.icon:bgColor};">{users.ipMatch.icon:text}</div>
|
<!-- BEGIN users.ipMatch -->
|
||||||
<!-- ENDIF users.ipMatch.picture -->
|
<br>
|
||||||
<a href="/uid/{users.ipMatch.uid}">{users.ipMatch.username}</a>
|
<!-- IF users.ipMatch.picture -->
|
||||||
<!-- END users.ipMatch -->
|
<img src="{users.ipMatch.picture}" class="user-img"/>
|
||||||
</td>
|
<!-- ELSE -->
|
||||||
<td class="hidden-xs">
|
<div class="user-img avatar avatar-sm" style="background-color: {users.ipMatch.icon:bgColor};">{users.ipMatch.icon:text}</div>
|
||||||
<span class="timeago" title="{users.timestampISO}"></span>
|
<!-- ENDIF users.ipMatch.picture -->
|
||||||
</td>
|
<a href="/uid/{users.ipMatch.uid}">{users.ipMatch.username}</a>
|
||||||
|
<!-- END users.ipMatch -->
|
||||||
<!-- BEGIN users.customRows -->
|
</td>
|
||||||
<td class="hidden-xs">{users.customRows.value}</td>
|
<td class="hidden-xs">
|
||||||
<!-- END users.customRows -->
|
<span class="timeago" title="{users.timestampISO}"></span>
|
||||||
|
</td>
|
||||||
<td>
|
|
||||||
<div class="btn-group pull-right">
|
|
||||||
<button class="btn btn-success btn-xs" data-action="accept"><i class="fa fa-check"></i></button>
|
|
||||||
<button class="btn btn-danger btn-xs" data-action="delete"><i class="fa fa-times"></i></button>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<!-- END users -->
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- IMPORT partials/paginator.tpl -->
|
<!-- BEGIN users.customRows -->
|
||||||
</div>
|
<td class="hidden-xs">{users.customRows.value}</td>
|
||||||
|
<!-- END users.customRows -->
|
||||||
|
|
||||||
<div class="invitations panel panel-success">
|
<td>
|
||||||
<div class="panel-heading">
|
<div class="btn-group pull-right">
|
||||||
[[admin/manage/registration:invitations]]
|
<button class="btn btn-success btn-xs" data-action="accept"><i class="fa fa-check"></i></button>
|
||||||
</div>
|
<button class="btn btn-danger btn-xs" data-action="delete"><i class="fa fa-times"></i></button>
|
||||||
<p class="panel-body">
|
</div>
|
||||||
[[admin/manage/registration:invitations.description]]
|
</td>
|
||||||
</p>
|
</tr>
|
||||||
<div class="table-responsive">
|
<!-- END users -->
|
||||||
<table class="table table-striped invites-list">
|
</tbody>
|
||||||
<tr>
|
</table>
|
||||||
<th>[[admin/manage/registration:invitations.inviter-username]]</th>
|
</div>
|
||||||
<th>[[admin/manage/registration:invitations.invitee-email]]</th>
|
|
||||||
<th>[[admin/manage/registration:invitations.invitee-username]]</th>
|
<!-- IMPORT partials/paginator.tpl -->
|
||||||
</tr>
|
</div>
|
||||||
<!-- BEGIN invites -->
|
|
||||||
<!-- BEGIN invites.invitations -->
|
<div class="invitations panel panel-success">
|
||||||
<tr data-invitation-mail="{invites.invitations.email}"
|
<div class="panel-heading">
|
||||||
data-invited-by="{invites.username}">
|
[[admin/manage/registration:invitations]]
|
||||||
<td class ="invited-by"><!-- IF @first -->{invites.username}<!-- ENDIF @first --></td>
|
</div>
|
||||||
<td>{invites.invitations.email}</td>
|
<p class="panel-body">
|
||||||
<td>{invites.invitations.username}
|
[[admin/manage/registration:invitations.description]]
|
||||||
<div class="btn-group pull-right">
|
</p>
|
||||||
<button class="btn btn-danger btn-xs" data-action="delete"><i class="fa fa-times"></i></button>
|
<div class="table-responsive">
|
||||||
</div>
|
<table class="table table-striped invites-list">
|
||||||
</td>
|
<thead>
|
||||||
</tr>
|
<tr>
|
||||||
<!-- END invites.invitations -->
|
<th>[[admin/manage/registration:invitations.inviter-username]]</th>
|
||||||
<!-- END invites -->
|
<th>[[admin/manage/registration:invitations.invitee-email]]</th>
|
||||||
</table>
|
<th>[[admin/manage/registration:invitations.invitee-username]]</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<!-- BEGIN invites -->
|
||||||
|
<!-- BEGIN invites.invitations -->
|
||||||
|
<tr data-invitation-mail="{invites.invitations.email}"
|
||||||
|
data-invited-by="{invites.username}">
|
||||||
|
<td class ="invited-by"><!-- IF @first -->{invites.username}<!-- ENDIF @first --></td>
|
||||||
|
<td>{invites.invitations.email}</td>
|
||||||
|
<td>{invites.invitations.username}
|
||||||
|
<div class="btn-group pull-right">
|
||||||
|
<button class="btn btn-danger btn-xs" data-action="delete"><i class="fa fa-times"></i></button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- END invites.invitations -->
|
||||||
|
<!-- END invites -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -0,0 +1,79 @@
|
|||||||
|
'use strict';
|
||||||
|
/*global require, after, before*/
|
||||||
|
|
||||||
|
|
||||||
|
var async = require('async');
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
|
var db = require('./mocks/databasemock');
|
||||||
|
var groups = require('../src/groups');
|
||||||
|
var user = require('../src/user');
|
||||||
|
var blacklist = require('../src/meta/blacklist');
|
||||||
|
|
||||||
|
describe('blacklist', function () {
|
||||||
|
|
||||||
|
var adminUid;
|
||||||
|
|
||||||
|
before(function (done) {
|
||||||
|
groups.resetCache();
|
||||||
|
user.create({username: 'admin'}, function (err, uid) {
|
||||||
|
assert.ifError(err);
|
||||||
|
adminUid = uid;
|
||||||
|
groups.join('administrators', adminUid, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var socketBlacklist = require('../src/socket.io/blacklist');
|
||||||
|
var rules = '1.1.1.1\n2.2.2.2\n::ffff:0:2.2.2.2\n127.0.0.1\n192.168.100.0/22';
|
||||||
|
|
||||||
|
it('should validate blacklist', function (done) {
|
||||||
|
socketBlacklist.validate({uid: adminUid}, {
|
||||||
|
rules: rules
|
||||||
|
}, function (err, data) {
|
||||||
|
assert.ifError(err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error if not admin', function (done) {
|
||||||
|
socketBlacklist.save({uid: 0}, rules, function (err) {
|
||||||
|
assert.equal(err.message, '[[error:no-privileges]]');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should save blacklist', function (done) {
|
||||||
|
socketBlacklist.save({uid: adminUid}, rules, function (err) {
|
||||||
|
assert.ifError(err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass ip test against blacklist async', function (done) {
|
||||||
|
blacklist.test('3.3.3.3', function (err) {
|
||||||
|
assert.ifError(err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass ip test against blacklist sync', function (done) {
|
||||||
|
assert(!blacklist.test('3.3.3.3'));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail ip test against blacklist async', function (done) {
|
||||||
|
blacklist.test('1.1.1.1', function (err) {
|
||||||
|
assert.equal(err.message, '[[error:blacklisted-ip]]');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail ip test against blacklist sync', function (done) {
|
||||||
|
assert(blacklist.test('1.1.1.1'));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(function (done) {
|
||||||
|
db.emptydb(done);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue