mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-31 19:15:58 +01:00
closes #4800
This commit is contained in:
@@ -57,6 +57,13 @@
|
|||||||
"post-edit-duration-expired-days": "You are only allowed to edit posts for %1 day(s) after posting",
|
"post-edit-duration-expired-days": "You are only allowed to edit posts for %1 day(s) after posting",
|
||||||
"post-edit-duration-expired-days-hours": "You are only allowed to edit posts for %1 day(s) %2 hour(s) after posting",
|
"post-edit-duration-expired-days-hours": "You are only allowed to edit posts for %1 day(s) %2 hour(s) after posting",
|
||||||
|
|
||||||
|
"post-delete-duration-expired": "You are only allowed to delete posts for %1 second(s) after posting",
|
||||||
|
"post-delete-duration-expired-minutes": "You are only allowed to delete posts for %1 minute(s) after posting",
|
||||||
|
"post-delete-duration-expired-minutes-seconds": "You are only allowed to delete posts for %1 minute(s) %2 second(s) after posting",
|
||||||
|
"post-delete-duration-expired-hours": "You are only allowed to delete posts for %1 hour(s) after posting",
|
||||||
|
"post-delete-duration-expired-hours-minutes": "You are only allowed to delete posts for %1 hour(s) %2 minute(s) after posting",
|
||||||
|
"post-delete-duration-expired-days": "You are only allowed to delete posts for %1 day(s) after posting",
|
||||||
|
"post-delete-duration-expired-days-hours": "You are only allowed to delete posts for %1 day(s) %2 hour(s) after posting",
|
||||||
|
|
||||||
"content-too-short": "Please enter a longer post. Posts should contain at least %1 character(s).",
|
"content-too-short": "Please enter a longer post. Posts should contain at least %1 character(s).",
|
||||||
"content-too-long": "Please enter a shorter post. Posts can't be longer than %1 character(s).",
|
"content-too-long": "Please enter a shorter post. Posts can't be longer than %1 character(s).",
|
||||||
|
|||||||
@@ -171,43 +171,55 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator
|
|||||||
|
|
||||||
var timestamp = parseInt(getData(btn, 'data-timestamp'), 10);
|
var timestamp = parseInt(getData(btn, 'data-timestamp'), 10);
|
||||||
var postEditDuration = parseInt(ajaxify.data.postEditDuration, 10);
|
var postEditDuration = parseInt(ajaxify.data.postEditDuration, 10);
|
||||||
if (!ajaxify.data.privileges.isAdminOrMod && postEditDuration && Date.now() - timestamp > postEditDuration * 1000) {
|
|
||||||
var numDays = Math.floor(postEditDuration / 86400);
|
|
||||||
var numHours = Math.floor((postEditDuration % 86400) / 3600);
|
|
||||||
var numMinutes = Math.floor(((postEditDuration % 86400) % 3600) / 60);
|
|
||||||
var numSeconds = ((postEditDuration % 86400) % 3600) % 60;
|
|
||||||
var msg = '[[error:post-edit-duration-expired, ' + postEditDuration + ']]';
|
|
||||||
if (numDays) {
|
|
||||||
if (numHours) {
|
|
||||||
msg = '[[error:post-edit-duration-expired-days-hours, ' + numDays + ', ' + numHours + ']]';
|
|
||||||
} else {
|
|
||||||
msg = '[[error:post-edit-duration-expired-days, ' + numDays + ']]';
|
|
||||||
}
|
|
||||||
} else if (numHours) {
|
|
||||||
if (numMinutes) {
|
|
||||||
msg = '[[error:post-edit-duration-expired-hours-minutes, ' + numHours + ', ' + numMinutes + ']]';
|
|
||||||
} else {
|
|
||||||
msg = '[[error:post-edit-duration-expired-hours, ' + numHours + ']]';
|
|
||||||
}
|
|
||||||
} else if (numMinutes) {
|
|
||||||
if (numSeconds) {
|
|
||||||
msg = '[[error:post-edit-duration-expired-minutes-seconds, ' + numMinutes + ', ' + numSeconds + ']]';
|
|
||||||
} else {
|
|
||||||
msg = '[[error:post-edit-duration-expired-minutes, ' + numMinutes + ']]';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return app.alertError(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
$(window).trigger('action:composer.post.edit', {
|
if (checkDuration(postEditDuration, timestamp, 'post-edit-duration-expired')) {
|
||||||
pid: getData(btn, 'data-pid')
|
$(window).trigger('action:composer.post.edit', {
|
||||||
});
|
pid: getData(btn, 'data-pid')
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
postContainer.on('click', '[component="post/delete"]', function() {
|
postContainer.on('click', '[component="post/delete"]', function() {
|
||||||
togglePostDelete($(this), tid);
|
var btn = $(this);
|
||||||
|
var timestamp = parseInt(getData(btn, 'data-timestamp'), 10);
|
||||||
|
var postDeleteDuration = parseInt(ajaxify.data.postDeleteDuration, 10);
|
||||||
|
if (checkDuration(postDeleteDuration, timestamp, 'post-delete-duration-expired')) {
|
||||||
|
togglePostDelete($(this), tid);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function checkDuration(duration, postTimestamp, languageKey) {
|
||||||
|
if (!ajaxify.data.privileges.isAdminOrMod && duration && Date.now() - postTimestamp > duration * 1000) {
|
||||||
|
var numDays = Math.floor(duration / 86400);
|
||||||
|
var numHours = Math.floor((duration % 86400) / 3600);
|
||||||
|
var numMinutes = Math.floor(((duration % 86400) % 3600) / 60);
|
||||||
|
var numSeconds = ((duration % 86400) % 3600) % 60;
|
||||||
|
var msg = '[[error:' + languageKey + ', ' + duration + ']]';
|
||||||
|
if (numDays) {
|
||||||
|
if (numHours) {
|
||||||
|
msg = '[[error:' + languageKey + '-days-hours, ' + numDays + ', ' + numHours + ']]';
|
||||||
|
} else {
|
||||||
|
msg = '[[error:' + languageKey + '-days, ' + numDays + ']]';
|
||||||
|
}
|
||||||
|
} else if (numHours) {
|
||||||
|
if (numMinutes) {
|
||||||
|
msg = '[[error:' + languageKey + '-hours-minutes, ' + numHours + ', ' + numMinutes + ']]';
|
||||||
|
} else {
|
||||||
|
msg = '[[error:' + languageKey + '-hours, ' + numHours + ']]';
|
||||||
|
}
|
||||||
|
} else if (numMinutes) {
|
||||||
|
if (numSeconds) {
|
||||||
|
msg = '[[error:' + languageKey + '-minutes-seconds, ' + numMinutes + ', ' + numSeconds + ']]';
|
||||||
|
} else {
|
||||||
|
msg = '[[error:' + languageKey + '-minutes, ' + numMinutes + ']]';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
app.alertError(msg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
postContainer.on('click', '[component="post/restore"]', function() {
|
postContainer.on('click', '[component="post/restore"]', function() {
|
||||||
togglePostDelete($(this), tid);
|
togglePostDelete($(this), tid);
|
||||||
});
|
});
|
||||||
@@ -394,9 +406,9 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator
|
|||||||
}
|
}
|
||||||
|
|
||||||
function togglePostDelete(button, tid) {
|
function togglePostDelete(button, tid) {
|
||||||
var pid = getData(button, 'data-pid'),
|
var pid = getData(button, 'data-pid');
|
||||||
postEl = components.get('post', 'pid', pid),
|
var postEl = components.get('post', 'pid', pid);
|
||||||
action = !postEl.hasClass('deleted') ? 'delete' : 'restore';
|
var action = !postEl.hasClass('deleted') ? 'delete' : 'restore';
|
||||||
|
|
||||||
postAction(action, pid, tid);
|
postAction(action, pid, tid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -264,7 +264,8 @@ topicsController.get = function(req, res, callback) {
|
|||||||
data['downvote:disabled'] = parseInt(meta.config['downvote:disabled'], 10) === 1;
|
data['downvote:disabled'] = parseInt(meta.config['downvote:disabled'], 10) === 1;
|
||||||
data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1;
|
data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1;
|
||||||
data.bookmarkThreshold = parseInt(meta.config.bookmarkThreshold, 10) || 5;
|
data.bookmarkThreshold = parseInt(meta.config.bookmarkThreshold, 10) || 5;
|
||||||
data.postEditDuration = parseInt(meta.config.postEditDuration, 10);
|
data.postEditDuration = parseInt(meta.config.postEditDuration, 10) || 0;
|
||||||
|
data.postDeleteDuration = parseInt(meta.config.postDeleteDuration, 10) || 0;
|
||||||
data.scrollToMyPost = settings.scrollToMyPost;
|
data.scrollToMyPost = settings.scrollToMyPost;
|
||||||
data.rssFeedUrl = nconf.get('relative_path') + '/topic/' + data.tid + '.rss';
|
data.rssFeedUrl = nconf.get('relative_path') + '/topic/' + data.tid + '.rss';
|
||||||
data.pagination = pagination.create(currentPage, pageCount);
|
data.pagination = pagination.create(currentPage, pageCount);
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ module.exports = function(Posts) {
|
|||||||
return next(new Error('[[error:post-already-restored]]'));
|
return next(new Error('[[error:post-already-restored]]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
privileges.posts.canEdit(pid, uid, next);
|
privileges.posts.canDelete(pid, uid, next);
|
||||||
},
|
},
|
||||||
function (canEdit, next) {
|
function (canDelete, next) {
|
||||||
if (!canEdit) {
|
if (!canDelete) {
|
||||||
return next(new Error('[[error:no-privileges]]'));
|
return next(new Error('[[error:no-privileges]]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -150,6 +150,38 @@ module.exports = function(privileges) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
privileges.posts.canDelete = function(pid, uid, callback) {
|
||||||
|
var postData;
|
||||||
|
async.waterfall([
|
||||||
|
function(next) {
|
||||||
|
posts.getPostFields(pid, ['tid', 'timestamp'], next);
|
||||||
|
},
|
||||||
|
function(_postData, next) {
|
||||||
|
postData = _postData;
|
||||||
|
async.parallel({
|
||||||
|
isAdminOrMod: async.apply(isAdminOrMod, pid, uid),
|
||||||
|
isLocked: async.apply(topics.isLocked, postData.tid),
|
||||||
|
isOwner: async.apply(posts.isOwner, pid, uid)
|
||||||
|
}, next);
|
||||||
|
}
|
||||||
|
], function(err, results) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
if (results.isAdminOrMod) {
|
||||||
|
return callback(null, true);
|
||||||
|
}
|
||||||
|
if (results.isLocked) {
|
||||||
|
return callback(new Error('[[error:topic-locked]]'));
|
||||||
|
}
|
||||||
|
var postDeleteDuration = parseInt(meta.config.postDeleteDuration, 10);
|
||||||
|
if (postDeleteDuration && (Date.now() - parseInt(postData.timestamp, 10) > postDeleteDuration * 1000)) {
|
||||||
|
return callback(new Error('[[error:post-delete-duration-expired, ' + meta.config.postDeleteDuration + ']]'));
|
||||||
|
}
|
||||||
|
callback(null, results.isOwner);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
privileges.posts.canMove = function(pid, uid, callback) {
|
privileges.posts.canMove = function(pid, uid, callback) {
|
||||||
posts.isMain(pid, function(err, isMain) {
|
posts.isMain(pid, function(err, isMain) {
|
||||||
if (err || isMain) {
|
if (err || isMain) {
|
||||||
|
|||||||
@@ -48,6 +48,10 @@
|
|||||||
<label for="postEditDuration">Number of seconds users are allowed to edit posts after posting. (0 disabled)</label>
|
<label for="postEditDuration">Number of seconds users are allowed to edit posts after posting. (0 disabled)</label>
|
||||||
<input id="postEditDuration" type="text" class="form-control" value="0" data-field="postEditDuration">
|
<input id="postEditDuration" type="text" class="form-control" value="0" data-field="postEditDuration">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="postDeleteDuration">Number of seconds users are allowed to delete posts after posting. (0 disabled)</label>
|
||||||
|
<input id="postDeleteDuration" type="text" class="form-control" value="0" data-field="postDeleteDuration">
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="minimumTitleLength">Minimum Title Length</label>
|
<label for="minimumTitleLength">Minimum Title Length</label>
|
||||||
<input id="minimumTitleLength" type="text" class="form-control" value="3" data-field="minimumTitleLength">
|
<input id="minimumTitleLength" type="text" class="form-control" value="3" data-field="minimumTitleLength">
|
||||||
|
|||||||
Reference in New Issue
Block a user