Version bump

This commit is contained in:
Neil Lalonde 2017-02-13 16:46:20 -05:00
commit 4f00241488
238 changed files with 6833 additions and 2405 deletions

View File

@ -140,7 +140,7 @@ GEM
kgio (2.10.0)
libv8 (5.3.332.38.3)
listen (0.7.3)
logster (1.2.5)
logster (1.2.7)
loofah (2.0.3)
nokogiri (>= 1.5.9)
lru_redux (1.1.0)
@ -168,7 +168,7 @@ GEM
netrc (0.11.0)
nokogiri (1.6.8.1)
mini_portile2 (~> 2.1.0)
nokogumbo (1.4.7)
nokogumbo (1.4.10)
nokogiri
oauth (0.5.1)
oauth2 (1.0.0)
@ -206,7 +206,7 @@ GEM
omniauth-twitter (1.3.0)
omniauth-oauth (~> 1.1)
rack
onebox (1.7.7)
onebox (1.8.1)
fast_blank (>= 1.0.0)
htmlentities (~> 4.3.4)
moneta (~> 0.8)
@ -314,7 +314,7 @@ GEM
ruby-readability (0.7.0)
guess_html_encoding (>= 0.0.4)
nokogiri (>= 1.6.0)
sanitize (4.0.1)
sanitize (4.4.0)
crass (~> 1.0.2)
nokogiri (>= 1.4.4)
nokogumbo (~> 1.4.1)
@ -476,4 +476,4 @@ DEPENDENCIES
unicorn
BUNDLED WITH
1.13.7
1.14.3

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -1,16 +1,9 @@
import computed from 'ember-addons/ember-computed-decorators';
export default Ember.Controller.extend({
@computed('model.@each.enabled_setting')
adminRoutes() {
let routes = [];
this.get('model').forEach(p => {
if (this.siteSettings[p.get('enabled_setting')] && p.get('admin_route')) {
routes.push(p.get('admin_route'));
adminRoutes: function() {
return this.get('model').map(p => {
if (p.get('enabled')) {
return p.admin_route;
}
});
return routes;
}
}).compact();
}.property()
});

View File

@ -11,11 +11,11 @@
{{number report.yesterdayCount}} {{fa-icon "caret-up" class="up"}} {{fa-icon "caret-down" class="down"}}
</td>
<td class="value {{report.sevenDayTrend}}" title={{number report.sevenDayCountTitle}}>
<td class="value {{report.sevenDayTrend}}" title={{report.sevenDayCountTitle}}>
{{number report.lastSevenDaysCount}} {{fa-icon "caret-up" class="up"}} {{fa-icon "caret-down" class="down"}}
</td>
<td class="value {{report.thirtyDayTrend}}" title={{number report.thirtyDayCountTitle}}>
<td class="value {{report.thirtyDayTrend}}" title={{report.thirtyDayCountTitle}}>
{{number report.lastThirtyDaysCount}} {{fa-icon "caret-up" class="up"}} {{fa-icon "caret-down" class="down"}}
</td>

View File

@ -33,6 +33,7 @@
//= require ./discourse/models/permission-type
//= require ./discourse/models/user-action-group
//= require ./discourse/models/category
//= require ./discourse/models/input-validation
//= require ./discourse/lib/ajax-error
//= require ./discourse/lib/search
//= require ./discourse/lib/user-search

View File

@ -54,6 +54,10 @@ export default Ember.Component.extend({
if (!this.element || this.isDestroying || this.isDestroyed) { return; }
if (this.get('isAbsoluteUrl') && (this.get('composer.reply')||"").length === 0) {
// only feature links to external sites
if (this.get('composer.title').match(new RegExp("^https?:\\/\\/" + window.location.hostname, "i"))) { return; }
// Try to onebox. If success, update post body and title.
this.set('composer.loading', true);

View File

@ -1,7 +1,7 @@
import Button from 'discourse/components/d-button';
export default Button.extend({
label: 'topic.reply.topic.title',
label: 'topic.reply.title',
icon: 'reply',
action: 'showLogin'
});

View File

@ -84,7 +84,7 @@ export default Ember.Component.extend(CleansUp, {
_show(username, $target) {
// No user card for anon
if (this.siteSettings.hide_user_profiles_from_public && !this.currentUser) {
return true;
return false;
}
// XSS protection (should be encapsulated)

View File

@ -44,7 +44,8 @@ export default TextField.extend({
exclude: excludedUsernames(),
includeGroups,
allowedUsers,
includeMentionableGroups
includeMentionableGroups,
group: self.get("group")
});
return results;

View File

@ -57,6 +57,7 @@ export default Ember.Controller.extend({
application: Ember.inject.controller(),
replyAsNewTopicDraft: Em.computed.equal('model.draftKey', Composer.REPLY_AS_NEW_TOPIC_KEY),
replyAsNewPrivateMessageDraft: Em.computed.equal('model.draftKey', Composer.REPLY_AS_NEW_PRIVATE_MESSAGE_KEY),
checkedMessages: false,
messageCount: null,
showEditReason: false,
@ -478,7 +479,7 @@ export default Ember.Controller.extend({
}
// If user "created a new topic/post" or "replied as a new topic" successfully, remove the draft.
if (result.responseJson.action === "create_post" || this.get('replyAsNewTopicDraft')) {
if (result.responseJson.action === "create_post" || this.get('replyAsNewTopicDraft') || this.get('replyAsNewPrivateMessageDraft')) {
this.destroyDraft();
}
if (this.get('model.action') === 'edit') {

View File

@ -5,8 +5,9 @@ import { setting } from 'discourse/lib/computed';
import { on } from 'ember-addons/ember-computed-decorators';
import { emailValid } from 'discourse/lib/utilities';
import InputValidation from 'discourse/models/input-validation';
import PasswordValidation from "discourse/mixins/password-validation";
export default Ember.Controller.extend(ModalFunctionality, {
export default Ember.Controller.extend(ModalFunctionality, PasswordValidation, {
login: Ember.inject.controller(),
uniqueUsernameValidation: null,
@ -16,7 +17,6 @@ export default Ember.Controller.extend(ModalFunctionality, {
accountChallenge: 0,
formSubmitted: false,
rejectedEmails: Em.A([]),
rejectedPasswords: Em.A([]),
prefilledUsername: null,
userFields: null,
isDeveloper: false,
@ -85,10 +85,6 @@ export default Ember.Controller.extend(ModalFunctionality, {
});
}.property(),
passwordInstructions: function() {
return this.get('isDeveloper') ? I18n.t('user.password.instructions', {count: Discourse.SiteSettings.min_admin_password_length}) : I18n.t('user.password.instructions', {count: Discourse.SiteSettings.min_password_length});
}.property('isDeveloper'),
nameInstructions: function() {
return I18n.t(Discourse.SiteSettings.full_name_required ? 'user.name.instructions_required' : 'user.name.instructions');
}.property(),
@ -293,55 +289,6 @@ export default Ember.Controller.extend(ModalFunctionality, {
return( this.get('globalNicknameExists') || false );
},
// Validate the password
passwordValidation: function() {
if (!this.get('passwordRequired')) {
return InputValidation.create({ ok: true });
}
// If blank, fail without a reason
const password = this.get("accountPassword");
if (Ember.isEmpty(this.get('accountPassword'))) {
return InputValidation.create({ failed: true });
}
// If too short
const passwordLength = this.get('isDeveloper') ? Discourse.SiteSettings.min_admin_password_length : Discourse.SiteSettings.min_password_length;
if (password.length < passwordLength) {
return InputValidation.create({
failed: true,
reason: I18n.t('user.password.too_short')
});
}
if (this.get('rejectedPasswords').includes(password)) {
return InputValidation.create({
failed: true,
reason: I18n.t('user.password.common')
});
}
if (!Ember.isEmpty(this.get('accountUsername')) && this.get('accountPassword') === this.get('accountUsername')) {
return InputValidation.create({
failed: true,
reason: I18n.t('user.password.same_as_username')
});
}
if (!Ember.isEmpty(this.get('accountEmail')) && this.get('accountPassword') === this.get('accountEmail')) {
return InputValidation.create({
failed: true,
reason: I18n.t('user.password.same_as_email')
});
}
// Looks good!
return InputValidation.create({
ok: true,
reason: I18n.t('user.password.ok')
});
}.property('accountPassword', 'rejectedPasswords.[]', 'accountUsername', 'accountEmail', 'isDeveloper'),
@on('init')
fetchConfirmationValue() {
return ajax('/users/hp.json').then(json => {

View File

@ -2,6 +2,7 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality';
import { categoryBadgeHTML } from 'discourse/helpers/category-link';
import computed from 'ember-addons/ember-computed-decorators';
import { propertyGreaterThan, propertyLessThan } from 'discourse/lib/computed';
import { on } from 'ember-addons/ember-computed-decorators';
function customTagArray(fieldName) {
return function() {
@ -17,9 +18,10 @@ export default Ember.Controller.extend(ModalFunctionality, {
loading: true,
viewMode: "side_by_side",
_changeViewModeOnMobile: function() {
if (this.site.mobileView) { this.set("viewMode", "inline"); }
}.on("init"),
@on('init')
_changeViewModeOnMobile() {
if (this.site && this.site.mobileView) { this.set("viewMode", "inline"); }
},
previousFeaturedLink: Em.computed.alias('model.featured_link_changes.previous'),
currentFeaturedLink: Em.computed.alias('model.featured_link_changes.current'),
@ -109,9 +111,14 @@ export default Ember.Controller.extend(ModalFunctionality, {
return !prevHidden && this.currentUser && this.currentUser.get('staff');
},
@computed("model.wiki", "model.last_revision", "model.current_revision")
displayEdit(wiki, lastRevision, currentRevision) {
return wiki && (lastRevision === currentRevision);
@computed("model.last_revision", "model.current_revision", "model.can_edit")
displayEdit(lastRevision, currentRevision, canEdit) {
return canEdit && (lastRevision === currentRevision);
},
@computed("model.wiki")
editButtonLabel(wiki) {
return `post.revisions.controls.${wiki ? 'edit_wiki' : 'edit_post'}`;
},
@computed()
@ -192,7 +199,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
hideVersion() { this.hide(this.get("model.post_id"), this.get("model.current_revision")); },
showVersion() { this.show(this.get("model.post_id"), this.get("model.current_revision")); },
editWiki() {
editPost() {
this.get('topicController').send('editPost', this.get('post'));
this.send('closeModal');
},

View File

@ -27,19 +27,22 @@ export default Ember.Controller.extend(ModalFunctionality, {
return Discourse.User.currentProp("admin");
}.property(),
disabled: function() {
if (this.get('model.saving')) return true;
if (Ember.isEmpty(this.get('emailOrUsername'))) return true;
const emailOrUsername = this.get('emailOrUsername').trim();
@computed('isAdmin', 'emailOrUsername', 'invitingToTopic', 'isPrivateTopic', 'model.groupNames', 'model.saving', 'model.details.can_invite_to')
disabled(isAdmin, emailOrUsername, invitingToTopic, isPrivateTopic, groupNames, saving, can_invite_to) {
if (saving) return true;
if (Ember.isEmpty(emailOrUsername)) return true;
const emailTrimmed = emailOrUsername.trim();
// when inviting to forum, email must be valid
if (!this.get('invitingToTopic') && !emailValid(emailOrUsername)) return true;
if (!invitingToTopic && !emailValid(emailTrimmed)) return true;
// normal users (not admin) can't invite users to private topic via email
if (!this.get('isAdmin') && this.get('isPrivateTopic') && emailValid(emailOrUsername)) return true;
if (!isAdmin && isPrivateTopic && emailValid(emailTrimmed)) return true;
// when inviting to private topic via email, group name must be specified
if (this.get('isPrivateTopic') && Ember.isEmpty(this.get('model.groupNames')) && emailValid(emailOrUsername)) return true;
if (this.get('model.details.can_invite_to')) return false;
if (isPrivateTopic && Ember.isEmpty(groupNames) && emailValid(emailTrimmed)) return true;
if (can_invite_to) return false;
return false;
}.property('isAdmin', 'emailOrUsername', 'invitingToTopic', 'isPrivateTopic', 'model.groupNames', 'model.saving'),
},
disabledCopyLink: function() {
if (this.get('hasCustomMessage')) return true;
@ -65,9 +68,17 @@ export default Ember.Controller.extend(ModalFunctionality, {
return this.get('model') !== this.currentUser;
}.property('model'),
showCopyInviteButton: function() {
return (!Discourse.SiteSettings.enable_sso && !this.get('isMessage'));
}.property('isMessage'),
@computed('model', 'model.details.can_invite_via_email')
canInviteViaEmail(model, can_invite_via_email) {
return (this.get('model') === this.currentUser) ?
true :
can_invite_via_email;
},
@computed('isMessage', 'canInviteViaEmail')
showCopyInviteButton(isMessage, canInviteViaEmail) {
return (canInviteViaEmail && !isMessage);
},
topicId: Ember.computed.alias('model.id'),
@ -83,32 +94,38 @@ export default Ember.Controller.extend(ModalFunctionality, {
}.property('invitingToTopic'),
// Show Groups? (add invited user to private group)
showGroups: function() {
return this.get('isAdmin') && (emailValid(this.get('emailOrUsername')) || this.get('isPrivateTopic') || !this.get('invitingToTopic')) && !Discourse.SiteSettings.enable_sso && Discourse.SiteSettings.enable_local_logins && !this.get('isMessage');
}.property('isAdmin', 'emailOrUsername', 'isPrivateTopic', 'isMessage', 'invitingToTopic'),
@computed('isAdmin', 'emailOrUsername', 'isPrivateTopic', 'isMessage', 'invitingToTopic', 'canInviteViaEmail')
showGroups(isAdmin, emailOrUsername, isPrivateTopic, isMessage, invitingToTopic, canInviteViaEmail) {
return isAdmin &&
canInviteViaEmail &&
!isMessage &&
(emailValid(emailOrUsername) || isPrivateTopic || !invitingToTopic);
},
showCustomMessage: function() {
return (this.get('model') === this.currentUser || emailValid(this.get('emailOrUsername')));
}.property('emailOrUsername'),
@computed('emailOrUsername')
showCustomMessage(emailOrUsername) {
return (this.get('model') === this.currentUser || emailValid(emailOrUsername));
},
// Instructional text for the modal.
inviteInstructions: function() {
if (Discourse.SiteSettings.enable_sso || !Discourse.SiteSettings.enable_local_logins) {
// inviting existing user when SSO enabled
@computed('isMessage', 'invitingToTopic', 'emailOrUsername', 'isPrivateTopic', 'isAdmin', 'canInviteViaEmail')
inviteInstructions(isMessage, invitingToTopic, emailOrUsername, isPrivateTopic, isAdmin, canInviteViaEmail) {
if (!canInviteViaEmail) {
// can't invite via email, only existing users
return I18n.t('topic.invite_reply.sso_enabled');
} else if (this.get('isMessage')) {
} else if (isMessage) {
// inviting to a message
return I18n.t('topic.invite_private.email_or_username');
} else if (this.get('invitingToTopic')) {
} else if (invitingToTopic) {
// inviting to a private/public topic
if (this.get('isPrivateTopic') && !this.get('isAdmin')) {
if (isPrivateTopic && !isAdmin) {
// inviting to a private topic and is not admin
return I18n.t('topic.invite_reply.to_username');
} else {
// when inviting to a topic, display instructions based on provided entity
if (Ember.isEmpty(this.get('emailOrUsername'))) {
if (Ember.isEmpty(emailOrUsername)) {
return I18n.t('topic.invite_reply.to_topic_blank');
} else if (emailValid(this.get('emailOrUsername'))) {
} else if (emailValid(emailOrUsername)) {
this.set("inviteIcon", "envelope");
return I18n.t('topic.invite_reply.to_topic_email');
} else {
@ -120,7 +137,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
// inviting to forum
return I18n.t('topic.invite_reply.to_forum');
}
}.property('isMessage', 'invitingToTopic', 'emailOrUsername'),
},
showGroupsClass: function() {
return this.get('isPrivateTopic') ? 'required' : 'optional';
@ -147,11 +164,12 @@ export default Ember.Controller.extend(ModalFunctionality, {
return this.get('isMessage') ? I18n.t('topic.invite_private.error') : I18n.t('topic.invite_reply.error');
}.property('isMessage'),
placeholderKey: function() {
return (Discourse.SiteSettings.enable_sso || !Discourse.SiteSettings.enable_local_logins) ?
'topic.invite_reply.username_placeholder' :
'topic.invite_private.email_or_username_placeholder';
}.property(),
@computed('canInviteViaEmail')
placeholderKey(canInviteViaEmail) {
return (canInviteViaEmail) ?
'topic.invite_private.email_or_username_placeholder' :
'topic.invite_reply.username_placeholder';
},
customMessagePlaceholder: function() {
return I18n.t('invite.custom_message_placeholder');

View File

@ -0,0 +1,64 @@
import { default as computed } from 'ember-addons/ember-computed-decorators';
import getUrl from 'discourse-common/lib/get-url';
import DiscourseURL from 'discourse/lib/url';
import { ajax } from 'discourse/lib/ajax';
import PasswordValidation from "discourse/mixins/password-validation";
export default Ember.Controller.extend(PasswordValidation, {
isDeveloper: Ember.computed.alias('model.is_developer'),
passwordRequired: true,
errorMessage: null,
successMessage: null,
requiresApproval: false,
redirected: false,
@computed()
continueButtonText() {
return I18n.t('password_reset.continue', {site_name: this.siteSettings.title});
},
@computed('redirectTo')
redirectHref(redirectTo) {
return Discourse.getURL(redirectTo || '/');
},
lockImageUrl: getUrl('/images/lock.svg'),
actions: {
submit() {
ajax({
url: `/users/password-reset/${this.get('model.token')}.json`,
type: 'PUT',
data: {
password: this.get('accountPassword')
}
}).then(result => {
if (result.success) {
this.set('successMessage', result.message);
this.set('redirectTo', result.redirect_to);
if (result.requires_approval) {
this.set('requiresApproval', true);
} else {
this.set('redirected', true);
DiscourseURL.redirectTo(result.redirect_to || '/');
}
} else {
if (result.errors && result.errors.password && result.errors.password.length > 0) {
this.get('rejectedPasswords').pushObject(this.get('accountPassword'));
this.get('rejectedPasswordsMessages').set(this.get('accountPassword'), result.errors.password[0]);
}
if (result.message) {
this.set('errorMessage', result.message);
}
}
}).catch(response => {
throw response;
});
},
done() {
this.set('redirected', true);
DiscourseURL.redirectTo(this.get('redirectTo') || '/');
}
}
});

View File

@ -656,11 +656,31 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
const quotedText = Quote.build(post, quoteState.buffer);
quoteState.clear();
composerController.open({
action: Composer.CREATE_TOPIC,
draftKey: Composer.REPLY_AS_NEW_TOPIC_KEY,
categoryId: this.get('model.category.id')
}).then(() => {
var options;
if (this.get('model.isPrivateMessage')) {
let users = this.get('model.details.allowed_users');
let groups = this.get('model.details.allowed_groups');
let usernames = [];
users.forEach(user => usernames.push(user.username));
groups.forEach(group => usernames.push(group.name));
usernames = usernames.join();
options = {
action: Composer.PRIVATE_MESSAGE,
archetypeId: 'private_message',
draftKey: Composer.REPLY_AS_NEW_PRIVATE_MESSAGE_KEY,
usernames: usernames
};
} else {
options = {
action: Composer.CREATE_TOPIC,
draftKey: Composer.REPLY_AS_NEW_TOPIC_KEY,
categoryId: this.get('model.category.id')
};
}
composerController.open(options).then(() => {
return Em.isEmpty(quotedText) ? "" : quotedText;
}).then(q => {
const postUrl = `${location.protocol}//${location.host}${post.get('url')}`;

View File

@ -13,7 +13,7 @@ registerUnbound('number', (orig, params) => {
let title = I18n.toNumber(orig, { precision: 0 });
if (params.numberKey) {
title = I18n.t(params.numberKey, { number: title, count: parseInt(title) });
title = I18n.t(params.numberKey, { number: title, count: parseInt(orig) });
}
let classNames = 'number';

View File

@ -5,13 +5,17 @@ import { addButton } from 'discourse/widgets/post-menu';
import { includeAttributes } from 'discourse/lib/transform-post';
import { addToolbarCallback } from 'discourse/components/d-editor';
import { addWidgetCleanCallback } from 'discourse/components/mount-widget';
import { createWidget, decorateWidget, changeSetting } from 'discourse/widgets/widget';
import { createWidget, reopenWidget, decorateWidget, changeSetting } from 'discourse/widgets/widget';
import { onPageChange } from 'discourse/lib/page-tracker';
import { preventCloak } from 'discourse/widgets/post-stream';
import { h } from 'virtual-dom';
import { addFlagProperty } from 'discourse/components/site-header';
import { addPopupMenuOptionsCallback } from 'discourse/controllers/composer';
import { extraConnectorClass } from 'discourse/lib/plugin-connectors';
import { addPostSmallActionIcon } from 'discourse/widgets/post-small-action';
// If you add any methods to the API ensure you bump up this number
const PLUGIN_API_VERSION = 0.8;
class PluginApi {
constructor(version, container) {
@ -307,6 +311,16 @@ class PluginApi {
return createWidget(name, args);
}
/**
* Exposes the widget update ability to plugins. Updates the widget
* registry for the given widget name to include the properties on args
* See `reopenWidget` in `discourse/widgets/widget` from more ifo.
**/
reopenWidget(name, args) {
return reopenWidget(name, args);
}
/**
* Adds a property that can be summed for calculating the flag counter
**/
@ -352,12 +366,23 @@ class PluginApi {
registerConnectorClass(outletName, connectorName, klass) {
extraConnectorClass(`${outletName}/${connectorName}`, klass);
}
/**
* Register a small icon to be used for custom small post actions
*
* ```javascript
* api.registerPostSmallActionIcon('assign-to', 'user-add');
* ```
**/
addPostSmallActionIcon(key, icon) {
addPostSmallActionIcon(key, icon);
}
}
let _pluginv01;
function getPluginApi(version) {
version = parseFloat(version);
if (version <= 0.6) {
if (version <= PLUGIN_API_VERSION) {
if (!_pluginv01) {
_pluginv01 = new PluginApi(version, Discourse.__container__);
}

View File

@ -6,7 +6,7 @@ var cache = {},
currentTerm,
oldSearch;
function performSearch(term, topicId, includeGroups, includeMentionableGroups, allowedUsers, resultsFn) {
function performSearch(term, topicId, includeGroups, includeMentionableGroups, allowedUsers, group, resultsFn) {
var cached = cache[term];
if (cached) {
resultsFn(cached);
@ -19,6 +19,7 @@ function performSearch(term, topicId, includeGroups, includeMentionableGroups, a
topic_id: topicId,
include_groups: includeGroups,
include_mentionable_groups: includeMentionableGroups,
group: group,
topic_allowed_users: allowedUsers }
});
@ -79,7 +80,8 @@ export default function userSearch(options) {
includeGroups = options.includeGroups,
includeMentionableGroups = options.includeMentionableGroups,
allowedUsers = options.allowedUsers,
topicId = options.topicId;
topicId = options.topicId,
group = options.group;
if (oldSearch) {
@ -105,10 +107,16 @@ export default function userSearch(options) {
resolve(CANCELLED_STATUS);
}, 5000);
debouncedSearch(term, topicId, includeGroups, includeMentionableGroups, allowedUsers, function(r) {
clearTimeout(clearPromise);
resolve(organizeResults(r, options));
});
debouncedSearch(term,
topicId,
includeGroups,
includeMentionableGroups,
allowedUsers,
group,
function(r) {
clearTimeout(clearPromise);
resolve(organizeResults(r, options));
});
});
}

View File

@ -170,7 +170,7 @@ export function validateUploadedFiles(files, opts) {
// CHROME ONLY: if the image was pasted, sets its name to a default one
if (typeof Blob !== "undefined" && typeof File !== "undefined") {
if (upload instanceof Blob && !(upload instanceof File) && upload.type === "image/png") { upload.name = "blob.png"; }
if (upload instanceof Blob && !(upload instanceof File) && upload.type === "image/png") { upload.name = "image.png"; }
}
opts = opts || {};

View File

@ -0,0 +1,71 @@
import InputValidation from 'discourse/models/input-validation';
import { default as computed } from 'ember-addons/ember-computed-decorators';
export default Ember.Mixin.create({
rejectedPasswords: null,
init() {
this._super();
this.set('rejectedPasswords', []);
this.set('rejectedPasswordsMessages', Ember.Map.create());
},
@computed('passwordMinLength')
passwordInstructions() {
return I18n.t('user.password.instructions', {count: this.get('passwordMinLength')});
},
@computed('isDeveloper')
passwordMinLength() {
return this.get('isDeveloper') ? this.siteSettings.min_admin_password_length : this.siteSettings.min_password_length;
},
@computed('accountPassword', 'passwordRequired', 'rejectedPasswords.[]', 'accountUsername', 'accountEmail', 'isDeveloper')
passwordValidation(password, passwordRequired, rejectedPasswords, accountUsername, accountEmail, isDeveloper) {
if (!passwordRequired) {
return InputValidation.create({ ok: true });
}
if (rejectedPasswords.includes(password)) {
return InputValidation.create({
failed: true,
reason: this.get('rejectedPasswordsMessages').get(password) || I18n.t('user.password.common')
});
}
// If blank, fail without a reason
if (Ember.isEmpty(password)) {
return InputValidation.create({ failed: true });
}
// If too short
const passwordLength = isDeveloper ? this.siteSettings.min_admin_password_length : this.siteSettings.min_password_length;
if (password.length < passwordLength) {
return InputValidation.create({
failed: true,
reason: I18n.t('user.password.too_short')
});
}
if (!Ember.isEmpty(accountUsername) && password === accountUsername) {
return InputValidation.create({
failed: true,
reason: I18n.t('user.password.same_as_username')
});
}
if (!Ember.isEmpty(accountEmail) && password === accountEmail) {
return InputValidation.create({
failed: true,
reason: I18n.t('user.password.same_as_email')
});
}
// Looks good!
return InputValidation.create({
ok: true,
reason: I18n.t('user.password.ok')
});
}
});

View File

@ -18,6 +18,7 @@ const CLOSED = 'closed',
REPLY = 'reply',
EDIT = 'edit',
REPLY_AS_NEW_TOPIC_KEY = "reply_as_new_topic",
REPLY_AS_NEW_PRIVATE_MESSAGE_KEY = "reply_as_new_private_message",
// When creating, these fields are moved into the post model from the composer model
_create_serializer = {
@ -814,7 +815,8 @@ Composer.reopenClass({
EDIT,
// Draft key
REPLY_AS_NEW_TOPIC_KEY
REPLY_AS_NEW_TOPIC_KEY,
REPLY_AS_NEW_PRIVATE_MESSAGE_KEY
});
export default Composer;

View File

@ -63,6 +63,7 @@ export default function() {
// User routes
this.route('users', { resetNamespace: true });
this.route('password-reset', { path: '/users/password-reset/:token' });
this.route('user', { path: '/users/:username', resetNamespace: true }, function() {
this.route('summary');
this.route('userActivity', { path: '/activity', resetNamespace: true }, function() {

View File

@ -0,0 +1,21 @@
import PreloadStore from 'preload-store';
import { ajax } from 'discourse/lib/ajax';
export default Discourse.Route.extend({
titleToken() {
return I18n.t('login.reset_password');
},
model(params) {
if (PreloadStore.get("password_reset")) {
return PreloadStore.getAndRemove("password_reset").then(json => _.merge(params, json));
}
},
afterModel(model) {
// confirm token here so email clients who crawl URLs don't invalidate the link
if (model) {
return ajax({ url: `/users/confirm-email-token/${model.token}.json`, dataType: 'json' });
}
}
});

View File

@ -15,7 +15,11 @@
{{#if topic.details.can_reply_as_new_topic}}
<div class='reply-as-new-topic'>
<a href {{action "replyAsNewTopic"}} aria-label={{i18n 'post.reply_as_new_topic'}} title={{i18n 'post.reply_as_new_topic'}}>{{fa-icon "plus"}}{{i18n 'topic.create'}}</a>
{{#if topic.isPrivateMessage}}
<a href {{action "replyAsNewTopic"}} aria-label={{i18n 'post.reply_as_new_private_message'}} title={{i18n 'post.reply_as_new_private_message'}}>{{fa-icon "plus"}}{{i18n 'user.new_private_message'}}</a>
{{else}}
<a href {{action "replyAsNewTopic"}} aria-label={{i18n 'post.reply_as_new_topic'}} title={{i18n 'post.reply_as_new_topic'}}>{{fa-icon "plus"}}{{i18n 'topic.create'}}</a>
{{/if}}
</div>
{{/if}}

View File

@ -68,8 +68,8 @@
{{d-button class="btn-primary create"
icon="reply"
action=replyToPost
label="topic.reply.topic.title"
title="topic.reply.topic.help"}}
label="topic.reply.title"
title="topic.reply.help"}}
{{/if}}
{{plugin-outlet name="after-topic-footer-main-buttons"

View File

@ -1,5 +1,5 @@
{{#d-modal-body title="history" maxHeight="80%"}}
<div>
<div id="revision">
<div id="revision-controls">
{{d-button action="loadFirstVersion" icon="fast-backward" title="post.revisions.controls.first" disabled=loadFirstDisabled}}
{{d-button action="loadPreviousVersion" icon="backward" title="post.revisions.controls.previous" disabled=loadPreviousDisabled}}
@ -12,6 +12,12 @@
{{d-button action="loadLastVersion" icon="fast-forward" title="post.revisions.controls.last" disabled=loadLastDisabled}}
</div>
{{#if displayEdit}}
{{d-button action="editPost"
icon="pencil"
label=editButtonLabel}}
{{/if}}
<div id="display-modes">
{{d-button action="displayInline"
icon="square-o"
@ -114,6 +120,8 @@
{{{bodyDiff}}}
{{/links-redirect}}
<hr>
{{#if displayRevert}}
{{d-button action="revertToVersion" icon="undo" label="post.revisions.controls.revert" class="btn-danger" disabled=loading}}
{{/if}}
@ -127,9 +135,9 @@
{{/if}}
{{#if displayEdit}}
{{d-button action="editWiki"
{{d-button action="editPost"
icon="pencil"
label="post.revisions.controls.edit_wiki"}}
label=editButtonLabel}}
{{/if}}
</div>
{{/d-modal-body}}

View File

@ -0,0 +1,41 @@
<div class="container password-reset clearfix">
<div class="pull-left col-image">
<img src={{lockImageUrl}} class="password-reset-img">
</div>
<div class="pull-left col-form">
{{#if successMessage}}
<p>{{successMessage}}</p>
{{#if requiresApproval}}
<p>{{i18n 'login.not_approved'}}</p>
{{else}}
{{#unless redirected}}
<a class="btn" href="{{redirectHref}}" {{action "done"}}>{{continueButtonText}}</a>
{{/unless}}
{{/if}}
{{else}}
<form>
<h2>{{i18n 'user.change_password.choose'}}</h2>
<div class="input">
{{password-field value=accountPassword type="password" id="new-account-password" capsLockOn=capsLockOn autofocus="autofocus"}}
&nbsp;{{input-tip validation=passwordValidation}}
</div>
<div class="instructions">
<div class="caps-lock-warning {{unless capsLockOn 'invisible'}}"><i class="fa fa-exclamation-triangle"></i> {{i18n 'login.caps_lock_warning'}}</div>
</div>
<button class='btn btn-primary' {{action "submit"}}>{{i18n 'user.change_password.set_password'}}</button>
{{#if errorMessage}}
<br/><br/>
<div class='alert alert-error'>{{errorMessage}}</div>
{{/if}}
</form>
{{/if}}
</div>
</div>

View File

@ -200,7 +200,9 @@
replyToPost=(action "replyToPost")
}}
{{else}}
{{d-button icon="reply" class="btn-primary" action="showLogin" label="topic.reply.topic.title"}}
<div id="topic-footer-button">
{{d-button icon="reply" class="btn-primary pull-right" action="showLogin" label="topic.reply.title"}}
</div>
{{/if}}
{{/if}}

View File

@ -148,7 +148,7 @@
<dt class="groups">{{i18n 'groups.title' count=model.displayGroups.length}}</dt>
<dd class='groups'>
{{#each model.displayGroups as |group|}}
<span>{{#link-to 'group' group class="group-link"}}{{group.name}}{{/link-to}}</span>
<span>{{#link-to 'group' group.name class="group-link"}}{{group.name}}{{/link-to}}</span>
{{/each}}
</dd>
{{/if}}

View File

@ -4,7 +4,11 @@ import { h } from 'virtual-dom';
createWidget('menu-links', {
html(attrs) {
const links = [].concat(attrs.contents());
const liOpts = { className: attrs.heading ? 'heading' : '' };
const liOpts = {};
if (attrs.heading) {
liOpts.className = 'header';
}
const result = [];
result.push(h('ul.menu-links.columned', links.map(l => h('li', liOpts, l))));

View File

@ -135,7 +135,7 @@ registerButton('reply', attrs => {
if (!attrs.canCreatePost) { return; }
if (!attrs.mobileView) {
args.label = 'topic.reply.post.title';
args.label = 'topic.reply.title';
}
return args;

View File

@ -27,6 +27,10 @@ const icons = {
'private_topic': 'envelope'
};
export function addPostSmallActionIcon(key, icon) {
icons[key] = icon;
};
export default createWidget('post-small-action', {
buildKey: attrs => `post-small-act-${attrs.id}`,
tagName: 'div.small-action.onscreen-post.clearfix',

View File

@ -85,7 +85,7 @@ export default createWidget('search-menu', {
query += `q=${encodeURIComponent(searchData.term)}`;
if (contextEnabled) {
if (contextEnabled && ctx) {
if (this.currentUser &&
ctx.id.toString().toLowerCase() === this.currentUser.username_lower &&
type === "private_messages") {

View File

@ -377,7 +377,7 @@ export default createWidget('topic-timeline', {
controls.push(this.attach('button', {
className: 'btn create',
icon: 'reply',
title: 'topic.reply.topic.help',
title: 'topic.reply.help',
action: 'replyToPost'
}));
}

View File

@ -125,6 +125,17 @@ export function createWidget(name, opts) {
return result;
}
export function reopenWidget(name, opts) {
let existing = _registry[name];
if (!existing) {
console.error(`Could not find widget ${name} in registry`);
return;
}
Object.keys(opts).forEach(k => existing.prototype[k] = opts[k]);
return existing;
}
export default class Widget {
constructor(attrs, register, opts) {
opts = opts || {};
@ -145,12 +156,12 @@ export default class Widget {
this.keyValueStore = register.lookup('key-value-store:main');
// Helps debug widgets
if (Ember.testing) {
if (Discourse.Environment === "development" || Ember.testing) {
const ds = this.defaultState(attrs);
if (typeof ds !== "object") {
Ember.warn(`defaultState must return an object`);
throw `defaultState must return an object`;
} else if (Object.keys(ds).length > 0 && !this.key) {
Ember.warn(`you need a key when using state ${this.name}`);
throw `you need a key when using state in ${this.name}`;
}
}

View File

@ -1,9 +1,13 @@
function escapeRegexp(text) {
return text.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
}
export function censor(text, censoredWords, censoredPattern) {
let patterns = [],
originalText = text;
if (censoredWords && censoredWords.length) {
patterns = censoredWords.split("|").map(t => { return "(" + t.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&') + ")"; });
patterns = censoredWords.split("|").map(t => `(${escapeRegexp(t)})`);
}
if (censoredPattern && censoredPattern.length > 0) {
@ -22,7 +26,7 @@ export function censor(text, censoredWords, censoredPattern) {
while (m && m[0]) {
if (m[0].length > originalText.length) { return originalText; } // regex is dangerous
const replacement = new Array(m[0].length+1).join('&#9632;');
text = text.replace(new RegExp("(\\b" + m[0] + "\\b)(?![^\\(]*\\))", "ig"), replacement);
text = text.replace(new RegExp(`(\\b${escapeRegexp(m[0])}\\b)(?![^\\(]*\\))`, "ig"), replacement);
m = censorRegexp.exec(text);
}
}

View File

@ -6,6 +6,15 @@
min-width: 96px;
text-align: center;
}
#revision {
overflow: auto;
}
#revision-controls {
display: inline-block;
}
#revisions .row:first-of-type {
margin-top: 10px;
}

View File

@ -64,6 +64,15 @@ $input-width: 220px;
}
}
.password-reset {
.instructions {
label {
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
}
}
}
// alternate login / create new account buttons should be de-emphasized
button#login-link, button#new-account-link

View File

@ -14,7 +14,7 @@ a.loading-onebox {
@include post-aside;
margin-top: 15px;
padding: 12px 25px 12px 12px;
padding: 12px;
font-size: 1em;
> .source {
margin-bottom: 12px;
@ -292,20 +292,22 @@ aside.onebox.twitterstatus .onebox-body {
margin-bottom: 0;
}
}
// thumbnail, oddly, ONLY applies to twitter avatar
.onebox.twitterstatus {
.thumbnail {
float: left;
width: 48px;
height: 48px;
}
p, .tweet {
float: left;
display: inline-block;
white-space: pre-wrap;
padding-top: 3px;
width: 85%;
margin-left: 58px;
}
.date {
clear: left;
padding-top: 5px;
margin-left: 58px;
}
}
@ -357,14 +359,29 @@ aside.onebox.stackexchange .onebox-body {
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
}
// mobile specific style
.mobile-view article.onebox-body {
border-top: none;
}
.onebox.xkcd .onebox-body {
img {
max-width: 100% !important;
float: none !important;
}
}
// pdf onebox
.onebox.pdf .onebox-body {
.pdf-onebox-logo {
width: 60px;
height: 50px;
float: left;
background: image-url("favicons/pdf_64px.png") no-repeat;
background-size: 48px 48px;
display: inline-block;
}
.filesize {
color: gray;
}
}
// mobile specific style
.mobile-view article.onebox-body {
border-top: none;
}

View File

@ -8,6 +8,8 @@
}
#revision-controls {
float: left;
padding-right: 5px;
.btn[disabled] {
cursor: not-allowed;
background-color: dark-light-diff($primary, $secondary, 90%, -60%);
@ -18,6 +20,9 @@
}
#display-modes {
text-align: right;
display: inline-block;
float: right;
.btn {
background-color:inherit;
color: dark-light-diff($primary, $secondary, 50%, -50%);

View File

@ -43,12 +43,6 @@
}
}
tr.instructions {
label {
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
}
}
.tos-agree {
margin-bottom: 12px;
}
@ -57,4 +51,24 @@
margin-top: 15px;
}
.instructions {
label {
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
}
}
}
.password-reset {
.col-form {
padding-top: 40px;
padding-left: 20px;
}
h2 {
margin-bottom: 12px;
}
.password-reset-img {
width: 200px;
height: 200px;
}
}

View File

@ -442,6 +442,10 @@ a.star {
}
}
#topic-footer-button {
width: 757px;
}
#suggested-topics {
clear: left;
padding: 20px 0 15px 0;

View File

@ -84,3 +84,32 @@ $input-width: 184px;
}
}
}
.password-reset {
margin-top: 30px;
.col-image {
padding-top: 12px;
}
.password-reset-img {
width: 50px;
height: 50px;
}
.col-form {
padding-left: 8px;
}
h2 {
margin-bottom: 12px;
}
.tip {
display: block;
margin: 6px 0;
max-width: 180px;
}
}
.discourse-touch .password-reset {
.instructions {
margin-bottom: 16px;
}
}

View File

@ -330,6 +330,11 @@ a.star {
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
}
#topic-footer-button {
width: 100px;
margin: 0 auto;
}
#suggested-topics {
clear: left;
padding: 20px 0 15px 0;

View File

@ -72,8 +72,7 @@ class Admin::UsersController < Admin::AdminController
def log_out
if @user
@user.auth_token = nil
@user.save!
@user.user_auth_tokens.destroy_all
@user.logged_out
render json: success_json
else

View File

@ -18,12 +18,7 @@ class GroupsController < ApplicationController
page_size = 30
page = params[:page]&.to_i || 0
groups = Group.order(name: :asc).where(visible: true)
if !guardian.is_admin?
groups = groups.where(automatic: false)
end
groups = Group.visible_groups(current_user)
count = groups.count
groups = groups.offset(page * page_size).limit(page_size)

View File

@ -48,8 +48,8 @@ class InvitesController < ApplicationController
guardian.ensure_can_invite_to_forum!(group_ids)
invite_exists = Invite.where(email: params[:email], invited_by_id: current_user.id).first
if invite_exists
guardian.ensure_can_send_multiple_invites!(current_user)
if invite_exists && !guardian.can_send_multiple_invites?(current_user)
return render json: failed_json, status: 422
end
begin
@ -70,8 +70,8 @@ class InvitesController < ApplicationController
guardian.ensure_can_invite_to_forum!(group_ids)
invite_exists = Invite.where(email: params[:email], invited_by_id: current_user.id).first
if invite_exists
guardian.ensure_can_send_multiple_invites!(current_user)
if invite_exists && !guardian.can_send_multiple_invites?(current_user)
return render json: failed_json, status: 422
end
begin

View File

@ -17,7 +17,7 @@ class MetadataController < ApplicationController
name: SiteSetting.title,
short_name: SiteSetting.title,
display: 'standalone',
orientation: 'any',
orientation: 'natural',
start_url: "#{Discourse.base_uri}/",
background_color: "##{ColorScheme.hex_for_name('secondary')}",
theme_color: "##{ColorScheme.hex_for_name('header_background')}",

View File

@ -74,13 +74,13 @@ class UploadsController < ApplicationController
return { errors: I18n.t("upload.file_missing") } if tempfile.nil?
# convert pasted images to HQ jpegs
if filename == "blob.png" && SiteSetting.convert_pasted_images_to_hq_jpg
jpeg_path = "#{File.dirname(tempfile.path)}/blob.jpg"
if filename == "image.png" && SiteSetting.convert_pasted_images_to_hq_jpg
jpeg_path = "#{File.dirname(tempfile.path)}/image.jpg"
OptimizedImage.ensure_safe_paths!(tempfile.path, jpeg_path)
`convert #{tempfile.path} -quality #{SiteSetting.convert_pasted_images_quality} #{jpeg_path}`
# only change the format of the image when JPG is at least 5% smaller
if File.size(jpeg_path) < File.size(tempfile.path) * 0.95
filename = "blob.jpg"
filename = "image.jpg"
content_type = "image/jpeg"
tempfile = File.open(jpeg_path)
else

View File

@ -405,8 +405,6 @@ class UsersController < ApplicationController
user_id = secure_session["password-#{token}"].to_i
@user = User.find(user_id) if user_id > 0
end
else
@invalid_token = true
end
if !@user
@ -419,17 +417,47 @@ class UsersController < ApplicationController
else
@user.password = params[:password]
@user.password_required!
@user.auth_token = nil
@user.user_auth_tokens.destroy_all
if @user.save
Invite.invalidate_for_email(@user.email) # invite link can't be used to log in anymore
secure_session["password-#{token}"] = nil
logon_after_password_reset
return redirect_to(wizard_path) if Wizard.user_requires_completion?(@user)
end
end
end
render layout: 'no_ember'
respond_to do |format|
format.html do
if @error
render layout: 'no_ember'
else
store_preloaded("password_reset", MultiJson.dump({ is_developer: UsernameCheckerService.is_developer?(@user.email) }))
end
return redirect_to(wizard_path) if Wizard.user_requires_completion?(@user)
end
format.json do
if request.put?
if @error || @user&.errors&.any?
render json: {
success: false,
message: @error,
errors: @user&.errors&.to_hash,
is_developer: UsernameCheckerService.is_developer?(@user.email)
}
else
render json: {
success: true,
message: @success,
requires_approval: !Guardian.new(@user).can_access_forum?,
redirect_to: Wizard.user_requires_completion?(@user) ? wizard_path : nil
}
end
else
render json: {is_developer: UsernameCheckerService.is_developer?(@user.email)}
end
end
end
end
def confirm_email_token
@ -559,7 +587,17 @@ class UsersController < ApplicationController
topic_id = topic_id.to_i if topic_id
topic_allowed_users = params[:topic_allowed_users] || false
results = UserSearch.new(term, topic_id: topic_id, topic_allowed_users: topic_allowed_users, searching_user: current_user).search
if params[:group].present?
@group = Group.find_by(name: params[:group])
end
results = UserSearch.new(term,
topic_id: topic_id,
topic_allowed_users: topic_allowed_users,
searching_user: current_user,
group: @group
).search
user_fields = [:username, :upload_avatar_template]
user_fields << :name if SiteSetting.enable_names?
@ -673,7 +711,7 @@ class UsersController < ApplicationController
private
def honeypot_value
Digest::SHA1::hexdigest("#{Discourse.current_hostname}:#{Discourse::Application.config.secret_token}")[0,15]
Digest::SHA1::hexdigest("#{Discourse.current_hostname}:#{GlobalSetting.safe_secret_key_base}")[0,15]
end
def challenge_value

View File

@ -24,14 +24,15 @@ class WebhooksController < ActionController::Base
event = params["event"]
message_id = params["Message-Id"].tr("<>", "")
to_address = params["recipient"]
# only handle soft bounces, because hard bounces are also handled
# by the "dropped" event and we don't want to increase bounce score twice
# for the same message
if event == "bounced".freeze && params["error"]["4."]
process_bounce(message_id, SiteSetting.soft_bounce_score)
process_bounce(message_id, to_address, SiteSetting.soft_bounce_score)
elsif event == "dropped".freeze
process_bounce(message_id, SiteSetting.hard_bounce_score)
process_bounce(message_id, to_address, SiteSetting.hard_bounce_score)
end
mailgun_success
@ -41,14 +42,15 @@ class WebhooksController < ActionController::Base
events = params["_json"] || [params]
events.each do |event|
message_id = (event["smtp-id"] || "").tr("<>", "")
to_address = event["email"]
if event["event"] == "bounce".freeze
if event["status"]["4."]
process_bounce(message_id, SiteSetting.soft_bounce_score)
process_bounce(message_id, to_address, SiteSetting.soft_bounce_score)
else
process_bounce(message_id, SiteSetting.hard_bounce_score)
process_bounce(message_id, to_address, SiteSetting.hard_bounce_score)
end
elsif event["event"] == "dropped".freeze
process_bounce(message_id, SiteSetting.hard_bounce_score)
process_bounce(message_id, to_address, SiteSetting.hard_bounce_score)
end
end
@ -59,11 +61,12 @@ class WebhooksController < ActionController::Base
events = params["_json"] || [params]
events.each do |event|
message_id = event["CustomID"]
to_address = event["email"]
if event["event"] == "bounce".freeze
if event["hard_bounce"]
process_bounce(message_id, SiteSetting.hard_bounce_score)
process_bounce(message_id, to_address, SiteSetting.hard_bounce_score)
else
process_bounce(message_id, SiteSetting.soft_bounce_score)
process_bounce(message_id, to_address, SiteSetting.soft_bounce_score)
end
end
end
@ -75,13 +78,13 @@ class WebhooksController < ActionController::Base
events = params["mandrill_events"]
events.each do |event|
message_id = event["msg"]["metadata"]["message_id"] rescue nil
next unless message_id
to_address = event["msg"]["email"] rescue nil
case event["event"]
when "hard_bounce"
process_bounce(message_id, SiteSetting.hard_bounce_score)
process_bounce(message_id, to_address, SiteSetting.hard_bounce_score)
when "soft_bounce"
process_bounce(message_id, SiteSetting.soft_bounce_score)
process_bounce(message_id, to_address, SiteSetting.soft_bounce_score)
end
end
@ -91,18 +94,22 @@ class WebhooksController < ActionController::Base
def sparkpost
events = params["_json"] || [params]
events.each do |event|
message_id = event["msys"]["message_event"]["rcpt_meta"]["message_id"] rescue nil
bounce_class = event["msys"]["message_event"]["bounce_class"] rescue nil
next unless message_id && bounce_class
message_event = event["msys"]["message_event"] rescue nil
next unless message_event
message_id = message_event["rcpt_meta"]["message_id"] rescue nil
to_address = message_event["rcpt_to"] rescue nil
bounce_class = message_event["bounce_class"] rescue nil
next unless bounce_class
bounce_class = bounce_class.to_i
# bounce class definitions: https://support.sparkpost.com/customer/portal/articles/1929896
if bounce_class < 80
if bounce_class == 10 || bounce_class == 25 || bounce_class == 30
process_bounce(message_id, SiteSetting.hard_bounce_score)
process_bounce(message_id, to_address, SiteSetting.hard_bounce_score)
else
process_bounce(message_id, SiteSetting.soft_bounce_score)
process_bounce(message_id, to_address, SiteSetting.soft_bounce_score)
end
end
end
@ -126,10 +133,10 @@ class WebhooksController < ActionController::Base
signature == OpenSSL::HMAC.hexdigest(digest, SiteSetting.mailgun_api_key, data)
end
def process_bounce(message_id, bounce_score)
return if message_id.blank?
def process_bounce(message_id, to_address, bounce_score)
return if message_id.blank? || to_address.blank?
email_log = EmailLog.find_by(message_id: message_id)
email_log = EmailLog.find_by(message_id: message_id, to_address: to_address)
return if email_log.nil?
email_log.update_columns(bounced: true)

View File

@ -15,13 +15,6 @@ module TopicsHelper
breadcrumb.push url: category.url, name: category.name
end
if SiteSetting.tagging_enabled && (tags = topic.tags).present?
tags.each do |tag|
url = "#{Discourse.base_url}/tags/#{tag.name}"
breadcrumb << {url: url, name: tag.name}
end
end
Plugin::Filter.apply(:topic_categories_breadcrumb, topic, breadcrumb)
end

View File

@ -33,11 +33,17 @@ module Jobs
Rails.logger.warn("Cooked post processor in FATAL state, bypassing. You need to urgently restart sidekiq\norig: #{orig_cooked}\nrecooked: #{recooked}\ncooked: #{cooked}\npost id: #{post.id}")
else
post.update_column(:cooked, cp.html)
extract_links(post)
post.publish_change_to_clients! :revised
end
end
end
# onebox may have added some links, so extract them now
def extract_links(post)
TopicLink.extract_from(post)
QuotedPost.extract_from(post)
end
end
end

View File

@ -21,7 +21,7 @@ module Jobs
.where(user_options: {email_digests: true})
.where("COALESCE(last_emailed_at, '2010-01-01') <= CURRENT_TIMESTAMP - ('1 MINUTE'::INTERVAL * user_options.digest_after_minutes)")
.where("COALESCE(last_seen_at, '2010-01-01') <= CURRENT_TIMESTAMP - ('1 MINUTE'::INTERVAL * user_options.digest_after_minutes)")
.where("COALESCE(last_seen_at, '2010-01-01') >= CURRENT_TIMESTAMP - ('1 DAY'::INTERVAL * #{SiteSetting.delete_digest_email_after_days})")
.where("COALESCE(last_seen_at, '2010-01-01') >= CURRENT_TIMESTAMP - ('1 DAY'::INTERVAL * #{SiteSetting.suppress_digest_email_after_days})")
# If the site requires approval, make sure the user is approved
if SiteSetting.must_approve_users?

View File

@ -13,6 +13,7 @@ module Jobs
ScoreCalculator.new.calculate
SchedulerStat.purge_old
Draft.cleanup!
UserAuthToken.cleanup!
end
end
end

View File

@ -74,6 +74,7 @@ class UserNotifications < ActionMailer::Base
end
end
# This is the "mailing list summary email"
def mailing_list(user, opts={})
@since = opts[:since] || 1.day.ago
@since_formatted = short_date(@since)

View File

@ -79,6 +79,8 @@ class DiscourseSingleSignOn < SingleSignOn
user.admin = admin unless admin.nil?
user.moderator = moderator unless moderator.nil?
user.title = title unless title.nil?
# optionally save the user and sso_record if they have changed
user.user_avatar.save! if user.user_avatar
user.save!

View File

@ -6,6 +6,35 @@ class GlobalSetting
end
end
VALID_SECRET_KEY = /^[0-9a-f]{128}$/
# this is named SECRET_TOKEN as opposed to SECRET_KEY_BASE
# for legacy reasons
REDIS_SECRET_KEY = 'SECRET_TOKEN'
# In Rails secret_key_base is used to encrypt the cookie store
# the cookie store contains session data
# Discourse also uses this secret key to digest user auth tokens
# This method will
# - use existing token if already set in ENV or discourse.conf
# - generate a token on the fly if needed and cache in redis
# - enforce rules about token format falling back to redis if needed
def self.safe_secret_key_base
@safe_secret_key_base ||= begin
token = secret_key_base
if token.blank? || token !~ VALID_SECRET_KEY
token = $redis.without_namespace.get(REDIS_SECRET_KEY)
unless token && token =~ VALID_SECRET_KEY
token = SecureRandom.hex(64)
$redis.without_namespace.set(REDIS_SECRET_KEY,token)
end
end
if !secret_key_base.blank? && token != secret_key_base
STDERR.puts "WARNING: DISCOURSE_SECRET_KEY_BASE is invalid, it was re-generated"
end
token
end
end
def self.load_defaults
default_provider = FileProvider.from(File.expand_path('../../../config/discourse_defaults.conf', __FILE__))
default_provider.keys.concat(@provider.keys).uniq.each do |key|
@ -37,29 +66,39 @@ class GlobalSetting
{"production" => hash}
end
# For testing purposes
def self.reset_redis_config!
@config = nil
end
def self.redis_config
@config ||=
begin
c = {}
c[:host] = redis_host if redis_host
c[:port] = redis_port if redis_port
c[:slave_host] = redis_slave_host if redis_slave_host
c[:slave_port] = redis_slave_port if redis_slave_port
if redis_slave_host && redis_slave_port
c[:slave_host] = redis_slave_host
c[:slave_port] = redis_slave_port
c[:connector] = DiscourseRedis::Connector
end
c[:password] = redis_password if redis_password.present?
c[:db] = redis_db if redis_db != 0
c[:db] = 1 if Rails.env == "test"
if redis_sentinels.present?
c[:sentinels] = redis_sentinels.split(",").map do |address|
host,port = address.split(":")
{host: host, port: port}
end.to_a
end
c[:connector] = DiscourseRedis::Connector
c.freeze
end
end
class BaseProvider
def self.coerce(setting)
return setting == "true" if setting == "true" || setting == "false"

View File

@ -63,6 +63,20 @@ class Group < ActiveRecord::Base
validates :alias_level, inclusion: { in: ALIAS_LEVELS.values}
scope :visible_groups, ->(user) {
groups = Group.order(name: :asc).where("groups.id > 0")
if !user || !user.admin
owner_group_ids = GroupUser.where(user: user, owner: true).pluck(:group_id)
groups = groups.where("
(groups.automatic = false AND groups.visible = true) OR groups.id IN (?)
", owner_group_ids)
end
groups
}
scope :mentionable, lambda {|user|
levels = [ALIAS_LEVELS[:everyone]]

View File

@ -59,7 +59,7 @@ class Invite < ActiveRecord::Base
if topic.private_message?
topic.grant_permission_to_user(user.email)
elsif topic.category && topic.category.groups.any?
if Guardian.new(invited_by).can_invite_to?(topic) && !SiteSetting.enable_sso
if Guardian.new(invited_by).can_invite_via_email?(topic)
(topic.category.groups - user.groups).each do |group|
group.add(user)
GroupActionLogger.new(Discourse.system_user, group).log_add_user_to_group(user)

View File

@ -454,7 +454,7 @@ class Post < ActiveRecord::Base
new_cooked = cook(raw, topic_id: topic_id, invalidate_oneboxes: opts.fetch(:invalidate_oneboxes, false))
old_cooked = cooked
self.update!(cooked: new_cooked, baked_at: Time.new, baked_version: BAKED_VERSION)
update_columns(cooked: new_cooked, baked_at: Time.new, baked_version: BAKED_VERSION)
# Extracts urls from the body
TopicLink.extract_from(self)

View File

@ -744,7 +744,7 @@ SQL
end
end
if username_or_email =~ /^.+@.+$/ && !SiteSetting.enable_sso && SiteSetting.enable_local_logins
if username_or_email =~ /^.+@.+$/ && Guardian.new(invited_by).can_invite_via_email?(self)
# rate limit topic invite
RateLimiter.new(invited_by, "topic-invitations-per-day", SiteSetting.max_topic_invitations_per_day, 1.day.to_i).performed!
@ -829,6 +829,9 @@ SQL
previous_banner = Topic.where(archetype: Archetype.banner).first
previous_banner.remove_banner!(user) if previous_banner.present?
UserProfile.where("dismissed_banner_key IS NOT NULL")
.update_all(dismissed_banner_key: nil)
self.archetype = Archetype.banner
self.add_moderator_post(user, I18n.t("archetypes.banner.message.make"))
self.save
@ -1118,6 +1121,7 @@ SQL
builder.where("p.post_number > 1")
builder.where("p.user_id != t.user_id")
builder.where("p.user_id in (:user_ids)", {user_ids: opts[:user_ids]}) if opts[:user_ids]
builder.where("p.post_type = :post_type", post_type: Post.types[:regular])
builder.where("EXTRACT(EPOCH FROM p.created_at - t.created_at) > 0")
builder.exec
end
@ -1136,11 +1140,11 @@ SQL
FROM (
SELECT t.id, t.created_at::date AS created_at, MIN(p.post_number) first_reply
FROM topics t
LEFT JOIN posts p ON p.topic_id = t.id AND p.user_id != t.user_id AND p.deleted_at IS NULL
LEFT JOIN posts p ON p.topic_id = t.id AND p.user_id != t.user_id AND p.deleted_at IS NULL AND p.post_type = #{Post.types[:regular]}
/*where*/
GROUP BY t.id
) tt
WHERE tt.first_reply IS NULL
WHERE tt.first_reply IS NULL OR tt.first_reply < 2
GROUP BY tt.created_at
ORDER BY tt.created_at
SQL
@ -1160,11 +1164,11 @@ SQL
FROM (
SELECT t.id, MIN(p.post_number) first_reply
FROM topics t
LEFT JOIN posts p ON p.topic_id = t.id AND p.user_id != t.user_id AND p.deleted_at IS NULL
LEFT JOIN posts p ON p.topic_id = t.id AND p.user_id != t.user_id AND p.deleted_at IS NULL AND p.post_type = #{Post.types[:regular]}
/*where*/
GROUP BY t.id
) tt
WHERE tt.first_reply IS NULL
WHERE tt.first_reply IS NULL OR tt.first_reply < 2
SQL
def self.with_no_response_total(opts={})

View File

@ -41,6 +41,7 @@ class User < ActiveRecord::Base
has_many :user_archived_messages, dependent: :destroy
has_many :email_change_requests, dependent: :destroy
has_many :directory_items, dependent: :delete_all
has_many :user_auth_tokens, dependent: :destroy
has_one :user_option, dependent: :destroy
@ -97,6 +98,7 @@ class User < ActiveRecord::Base
before_save :update_username_lower
before_save :ensure_password_is_hashed
after_save :expire_tokens_if_password_changed
after_save :automatic_group_membership
after_save :clear_global_notice_if_needed
after_save :refresh_avatar
@ -420,7 +422,6 @@ class User < ActiveRecord::Base
# special case for passwordless accounts
unless password.blank?
@raw_password = password
self.auth_token = nil
end
end
@ -922,6 +923,8 @@ class User < ActiveRecord::Base
end
def clear_global_notice_if_needed
return if id == Discourse::SYSTEM_USER_ID
if admin && SiteSetting.has_login_hint
SiteSetting.has_login_hint = false
SiteSetting.global_notice = ""
@ -933,14 +936,17 @@ class User < ActiveRecord::Base
end
def automatic_group_membership
user = User.find(self.id)
return unless user && user.active && !user.staged
Group.where(automatic: false)
.where("LENGTH(COALESCE(automatic_membership_email_domains, '')) > 0")
.each do |group|
domains = group.automatic_membership_email_domains.gsub('.', '\.')
user = User.find(self.id)
if user.reload.email =~ Regexp.new("@(#{domains})$", true) && !group.users.include?(user)
if user.email =~ Regexp.new("@(#{domains})$", true) && !group.users.include?(user)
group.add(user)
GroupActionLogger.new(Discourse.system_user, group).log_add_user_to_group(user)
end
@ -968,6 +974,18 @@ class User < ActiveRecord::Base
end
end
def expire_tokens_if_password_changed
# NOTE: setting raw password is the only valid way of changing a password
# the password field in the DB is actually hashed, nobody should be amending direct
if @raw_password
# Association in model may be out-of-sync
UserAuthToken.where(user_id: id).destroy_all
# We should not carry this around after save
@raw_password = nil
end
end
def hash_password(password, salt)
raise StandardError.new("password is too long") if password.size > User.max_password_length
Pbkdf2.hash_password(password, salt, Rails.configuration.pbkdf2_iterations, Rails.configuration.pbkdf2_algorithm)
@ -1073,7 +1091,7 @@ end
# username :string(60) not null
# created_at :datetime not null
# updated_at :datetime not null
# name :string
# name :string(255)
# seen_notification_id :integer default(0), not null
# last_posted_at :datetime
# email :string(513) not null
@ -1098,7 +1116,7 @@ end
# ip_address :inet
# moderator :boolean default(FALSE)
# blocked :boolean default(FALSE)
# title :string
# title :string(255)
# uploaded_avatar_id :integer
# locale :string(10)
# primary_group_id :integer

View File

@ -19,6 +19,7 @@ class UserAction < ActiveRecord::Base
GOT_PRIVATE_MESSAGE = 13
PENDING = 14
SOLVED = 15
ASSIGNED = 16
ORDER = Hash[*[
GOT_PRIVATE_MESSAGE,
@ -34,6 +35,7 @@ class UserAction < ActiveRecord::Base
BOOKMARK,
EDIT,
SOLVED,
ASSIGNED,
].each_with_index.to_a.flatten]
# note, this is temporary until we upgrade to rails 4

View File

@ -0,0 +1,170 @@
# frozen_string_literal: true
require 'digest/sha1'
class UserAuthToken < ActiveRecord::Base
belongs_to :user
ROTATE_TIME = 10.minutes
# used when token did not arrive at client
URGENT_ROTATE_TIME = 1.minute
attr_accessor :unhashed_auth_token
def self.generate!(info)
token = SecureRandom.hex(16)
hashed_token = hash_token(token)
user_auth_token = UserAuthToken.create!(
user_id: info[:user_id],
user_agent: info[:user_agent],
client_ip: info[:client_ip],
auth_token: hashed_token,
prev_auth_token: hashed_token,
rotated_at: Time.zone.now
)
user_auth_token.unhashed_auth_token = token
if SiteSetting.verbose_auth_token_logging
UserAuthTokenLog.create!(
action: 'generate',
user_auth_token_id: user_auth_token.id,
user_id: info[:user_id],
user_agent: info[:user_agent],
client_ip: info[:client_ip],
auth_token: hashed_token
)
end
user_auth_token
end
def self.lookup(unhashed_token, opts=nil)
mark_seen = opts && opts[:seen]
token = hash_token(unhashed_token)
expire_before = SiteSetting.maximum_session_age.hours.ago
user_token = find_by("(auth_token = :token OR
prev_auth_token = :token OR
(auth_token = :unhashed_token AND legacy)) AND created_at > :expire_before",
token: token, unhashed_token: unhashed_token, expire_before: expire_before)
token_expired =
user_token &&
user_token.auth_token_seen &&
user_token.prev_auth_token == token &&
user_token.prev_auth_token != user_token.auth_token &&
user_token.rotated_at > 1.minute.ago
if token_expired || !user_token
if SiteSetting.verbose_auth_token_logging
UserAuthTokenLog.create(
action: "miss token",
user_id: user_token&.user_id,
auth_token: token,
user_agent: opts && opts[:user_agent],
client_ip: opts && opts[:client_ip]
)
end
return nil
end
if mark_seen && user_token && !user_token.auth_token_seen && user_token.auth_token == token
user_token.update_columns(auth_token_seen: true)
if SiteSetting.verbose_auth_token_logging
UserAuthTokenLog.create(
action: "seen token",
user_auth_token_id: user_token.id,
user_id: user_token.user_id,
auth_token: user_token.auth_token,
user_agent: opts && opts[:user_agent],
client_ip: opts && opts[:client_ip]
)
end
end
user_token
end
def self.hash_token(token)
Digest::SHA1.base64digest("#{token}#{GlobalSetting.safe_secret_key_base}")
end
def self.cleanup!
if SiteSetting.verbose_auth_token_logging
UserAuthTokenLog.where('created_at < :time',
time: SiteSetting.maximum_session_age.hours.ago - ROTATE_TIME).delete_all
end
where('rotated_at < :time',
time: SiteSetting.maximum_session_age.hours.ago - ROTATE_TIME).delete_all
end
def rotate!(info=nil)
user_agent = (info && info[:user_agent] || self.user_agent)
client_ip = (info && info[:client_ip] || self.client_ip)
token = SecureRandom.hex(16)
result = UserAuthToken.exec_sql("
UPDATE user_auth_tokens
SET
auth_token_seen = false,
user_agent = :user_agent,
client_ip = :client_ip,
prev_auth_token = case when auth_token_seen then auth_token else prev_auth_token end,
auth_token = :new_token,
rotated_at = :now
WHERE id = :id AND (auth_token_seen or rotated_at < :safeguard_time)
", id: self.id,
user_agent: user_agent,
client_ip: client_ip&.to_s,
now: Time.zone.now,
new_token: UserAuthToken.hash_token(token),
safeguard_time: 30.seconds.ago
)
if result.cmdtuples > 0
reload
self.unhashed_auth_token = token
if SiteSetting.verbose_auth_token_logging
UserAuthTokenLog.create(
action: "rotate",
user_auth_token_id: id,
user_id: user_id,
auth_token: auth_token,
user_agent: user_agent,
client_ip: client_ip
)
end
true
else
false
end
end
end
# == Schema Information
#
# Table name: user_auth_tokens
#
# id :integer not null, primary key
# user_id :integer not null
# auth_token :string not null
# prev_auth_token :string
# user_agent :string
# auth_token_seen :boolean default(FALSE), not null
# legacy :boolean default(FALSE), not null
# client_ip :inet
# rotated_at :datetime
# created_at :datetime
# updated_at :datetime
#

View File

@ -0,0 +1,2 @@
class UserAuthTokenLog < ActiveRecord::Base
end

View File

@ -61,7 +61,8 @@ class UserHistory < ActiveRecord::Base
activate_user: 43,
change_readonly_mode: 44,
backup_download: 45,
backup_destroy: 46)
backup_destroy: 46,
notified_about_get_a_room: 47)
end
# Staff actions is a subset of all actions, used to audit actions taken by staff users.

View File

@ -10,11 +10,20 @@ class UserSearch
@topic_allowed_users = opts[:topic_allowed_users]
@searching_user = opts[:searching_user]
@limit = opts[:limit] || 20
@group = opts[:group]
@guardian = Guardian.new(@searching_user)
@guardian.ensure_can_see_group!(@group) if @group
end
def scoped_users
users = User.where(active: true, staged: false)
if @group
users = users.where('users.id IN (
SELECT user_id FROM group_users WHERE group_id = ?
)', @group.id)
end
unless @searching_user && @searching_user.staff?
users = users.not_suspended
end

View File

@ -24,7 +24,8 @@ class PostRevisionSerializer < ApplicationSerializer
:title_changes,
:user_changes,
:tags_changes,
:wiki
:wiki,
:can_edit
# Creates a field called field_name_changes with previous and
@ -100,6 +101,10 @@ class PostRevisionSerializer < ApplicationSerializer
object.post.wiki
end
def can_edit
scope.can_edit?(object.post)
end
def edit_reason
# only show 'edit_reason' when revisions are consecutive
current["edit_reason"] if scope.can_view_hidden_post_revisions? ||

View File

@ -115,6 +115,7 @@ class TopicViewSerializer < ApplicationSerializer
result[:can_recover] = true if scope.can_recover_topic?(object.topic)
result[:can_remove_allowed_users] = true if scope.can_remove_allowed_users?(object.topic)
result[:can_invite_to] = true if scope.can_invite_to?(object.topic)
result[:can_invite_via_email] = true if scope.can_invite_via_email?(object.topic)
result[:can_create_post] = true if scope.can_create?(Post, object.topic)
result[:can_reply_as_new_topic] = true if scope.can_reply_as_new_topic?(object.topic)
result[:can_flag_topic] = actions_summary.any? { |a| a[:can_act] }

View File

@ -2,7 +2,7 @@
<html lang="<%= SiteSetting.default_locale %>">
<head>
<meta charset="utf-8">
<title><%=SiteSetting.title%></title>
<title><%= content_for?(:title) ? yield(:title) + ' - ' + SiteSetting.title : SiteSetting.title %></title>
<meta name="description" content="">
<%= render partial: "layouts/head" %>
<%= render partial: "common/special_font_face" %>

View File

@ -49,6 +49,13 @@
<% end %>
<span itemprop='url'><b><a href='<%= @list.more_topics_url %>' rel='next' itemprop='name'><%= t 'next_page' %></a></b></span>
</div>
<% content_for :head do %>
<% if params[:page].to_i > 0 %>
<link rel="prev" href="<%= @list.prev_topics_url -%>">
<% end %>
<link rel="next" href="<%= @list.more_topics_url -%>">
<% end %>
<% end %>
<%- end %>

View File

@ -4,6 +4,12 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title><%= @topic_view.topic.title %></title>
<%= raw crawlable_meta_data(title: @topic_view.title, description: @topic_view.summary, image: @topic_view.image_url, read_time: @topic_view.read_time, like_count: @topic_view.like_count) %>
<% if @topic_view.prev_page %>
<link rel="prev" href="<%= @topic_view.prev_page_path -%>">
<% end %>
<% if @topic_view.next_page %>
<link rel="next" href="<%= @topic_view.next_page_path -%>">
<% end %>
</head>
<body>
<% @topic_view.posts.each do |post| %>

View File

@ -18,6 +18,23 @@
</div>
<% end %>
<% if SiteSetting.tagging_enabled %>
<% @tags = @topic_view.topic.tags %>
<% if @tags.present? %>
<div class='tags-list' itemscope itemtype='http://schema.org/ItemList'>
<% @tags.each do |tag| %>
<div itemprop='itemListElement' itemscope itemtype='http://schema.org/ListItem'>
<meta itemprop='url' content='<%= "#{Discourse.base_url}/tags/#{tag.name}" %>'>
<a href='<%= "#{Discourse.base_url}/tags/#{tag.name}" %>' itemprop='item'>
<span itemprop='name'><%= tag.name -%></span>
</a>
</div>
<% end %>
</div>
<% end %>
<% end %>
<%= server_plugin_outlet "topic_header" %>
<hr>
@ -25,7 +42,7 @@
<%- if include_crawler_content? %>
<% @topic_view.posts.each do |post| %>
<div itemscope itemtype='http://schema.org/Article'>
<div itemscope itemtype='http://schema.org/DiscussionForumPosting'>
<% if (u = post.user) %>
<div class='creator'>
<span>
@ -63,6 +80,15 @@
<% content_for :head do %>
<%= auto_discovery_link_tag(@topic_view, {action: :feed, slug: @topic_view.topic.slug, topic_id: @topic_view.topic.id}, title: t('rss_posts_in_topic', topic: @topic_view.title), type: 'application/rss+xml') %>
<%= raw crawlable_meta_data(title: @topic_view.title, description: @topic_view.summary, image: @topic_view.image_url, read_time: @topic_view.read_time, like_count: @topic_view.like_count) %>
<% if @topic_view.prev_page || @topic_view.next_page %>
<% if @topic_view.prev_page %>
<link rel="prev" href="<%= @topic_view.prev_page_path -%>">
<% end %>
<% if @topic_view.next_page %>
<link rel="next" href="<%= @topic_view.next_page_path -%>">
<% end %>
<% end %>
<% end %>
<% content_for(:title) { "#{@topic_view.page_title}" } %>

View File

@ -11,59 +11,18 @@
<% end %>
</div>
<% end %>
<%if @success%>
<p>
<%= @success %>
<%- if @requires_approval %>
<%= t 'login.not_approved' %>
<% else %>
<br>
<br>
<a class="btn" href="<%= path "/" %>"><%= t('password_reset.continue', site_name: SiteSetting.title) %></a>
<% end %>
</p>
<% else %>
<%if @user.present? %>
<h3>
<% if @user.has_password? %>
<%= t 'password_reset.choose_new' %>
<% else %>
<%= t 'password_reset.choose' %>
<% end %>
</h3>
<%=form_tag({}, method: :put) do %>
<p>
<span style="display: none;"><input name="username" type="text" value="<%= @user.username %>"></span>
<input id="user_password" name="password" size="30" type="password" maxlength="<%= User.max_password_length %>" onkeypress="capsLock(event)">
<label><%= t('js.user.password.instructions', count: @user.admin? ? SiteSetting.min_admin_password_length : SiteSetting.min_password_length) %></label>
</p>
<div id="capsLockWarning" class="caps-lock-warning" style="visibility:hidden"><i class="fa fa-exclamation-triangle"></i> <%= t 'js.login.caps_lock_warning' %></div>
<p>
<%=submit_tag( @user.has_password? ? t('password_reset.update') : t('password_reset.save'), class: 'btn')%>
</p>
<%end%>
<%end%>
<%end%>
</div>
<% content_for :title do %><%=t "password_reset.title" %><% end %>
<%- content_for(:no_ember_head) do %>
<meta name="referrer" content="never">
<%= script "ember_jquery" %>
<%= render_google_universal_analytics_code %>
<%- end %>
<script type="text/javascript">
document.getElementById('user_password').focus();
function capsLock(e) {
kc = e.keyCode?e.keyCode:e.which;
sk = e.shiftKey?e.shiftKey:((kc == 16)?true:false);
(((kc >= 65 && kc <= 90) && !sk)||((kc >= 97 && kc <= 122) && sk)) ? document.getElementById('capsLockWarning').style.visibility = 'visible' : document.getElementById('capsLockWarning').style.visibility = 'hidden';
}
$.ajax('<%= path "/users/confirm-email-token/#{params[:token]}" %>', {dataType: 'json'});
</script>
<%- content_for(:head) do %>
<meta name="referrer" content="never">
<%- end %>
<%= render_google_analytics_code %>

View File

@ -147,3 +147,6 @@ relative_url_root =
# this ensures backlog (ability of channels to catch up are capped)
# message bus default cap is 1000, we are winding it down to 100
message_bus_max_backlog_size = 100
# must be a 64 byte hex string, anything else will be ignored with a warning
secret_key_base =

View File

@ -4,14 +4,20 @@ end
Rails::Rack::Logger.class_eval do
def call_with_quiet_assets(env)
previous_level = Rails.logger.level
override = false
if (env['PATH_INFO'].index("/assets/") == 0) or
(env['PATH_INFO'].index("mini-profiler-resources") == 0)
Rails.logger.level = Logger::ERROR
if ::Logster::Logger === Rails.logger
override = true
Rails.logger.override_level = Logger::ERROR
end
end
call_without_quiet_assets(env).tap do
Rails.logger.level = previous_level
if override
Rails.logger.override_level = nil
end
end
end
alias_method_chain :call, :quiet_assets

View File

@ -1,14 +1,4 @@
# We have had lots of config issues with SECRET_TOKEN to avoid this mess we are moving it to redis
# if you feel strongly that it does not belong there use ENV['SECRET_TOKEN']
#
token = ENV['SECRET_TOKEN']
unless token
token = $redis.get('SECRET_TOKEN')
unless token && token.length == 128
token = SecureRandom.hex(64)
$redis.set('SECRET_TOKEN',token)
end
end
Discourse::Application.config.secret_token = token
Discourse::Application.config.secret_key_base = token
# Not fussed setting secret_token anymore, that is only required for
# backwards support of "seamless" upgrade from Rails 3.
# Discourse has shipped Rails 3 for a very long time.
Discourse::Application.config.secret_key_base = GlobalSetting.safe_secret_key_base

View File

@ -12,21 +12,24 @@ class SilenceLogger < Rails::Rack::Logger
end
def call(env)
prev_level = Rails.logger.level
path_info = env[PATH_INFO]
override = false
if env[HTTP_X_SILENCE_LOGGER] ||
@opts[:silenced].include?(path_info) ||
path_info.start_with?('/logs') ||
path_info.start_with?('/user_avatar') ||
path_info.start_with?('/letter_avatar')
Rails.logger.level = Logger::WARN
if ::Logster::Logger === Rails.logger
override = true
Rails.logger.override_level = Logger::WARN
end
@app.call(env)
else
super(env)
end
ensure
Rails.logger.level = prev_level
Rails.logger.override_level = nil if override
end
end

View File

@ -1530,11 +1530,8 @@ ar:
make_banner: "موضوع دعائي"
remove_banner: "إزالة موضوع دعائي"
reply:
post:
title: 'ردّ'
topic:
title: 'ردّ'
help: 'ابدأ بكتابة رد على هذا الموضوع'
title: 'ردّ'
help: 'ابدأ بكتابة رد على هذا الموضوع'
clear_pin:
title: "إلغاء التثبيت"
help: "إلغاء تثبيت الموضوع حتى لا يظهر في أعلى القائمة"

View File

@ -104,9 +104,13 @@ bs_BA:
google+: 'podijeli link na Google+'
email: 'pošalji ovaj link na email'
action_codes:
public_topic: "postavio ovu temu kao javno %{when}"
private_topic: "postavio ovu temu kao privatno %{when}"
split_topic: "podjeli ovu temu %{when}"
invited_user: "pozvan %{who} %{when}"
invited_group: "pozvan %{who} %{when}"
removed_user: "uklonjen %{who} %{when}"
removed_group: "ukloljen %{who} %{when}"
autoclosed:
enabled: 'zatvoren %{when}'
disabled: 'otvoren %{when}'
@ -126,8 +130,24 @@ bs_BA:
enabled: 'izlistan %{when}'
disabled: 'sklonjen %{when}'
topic_admin_menu: "topic admin actions"
wizard_required: "Vrijeme je za kofiguraciju vašeg foruma! <a href='%{url}' data-auto-route='true'>Startajte Setup Postavke</a>!"
emails_are_disabled: "Sve odlazeće email poruke su globalno onemogućene od strane administratora. Niti jedna notifikacija bilo kakve vrste neće biti poslana."
bootstrap_mode_enabled: "Kako bi lakše lansirali svoj novi sajt, trenutno ste u bootstrap modu. Svi novi korisnici će dobiti razinu povjerenja 1 i imati uključen sistematizovani dnevni e-mail pregleda promjena. Naknadno će biti automatski isključeno nakon što ukupan broj korisnika pređe brojku od %{min_users}."
bootstrap_mode_disabled: "Bootstrap mod će biti ugašen u sljedećih 24 sata."
s3:
regions:
us_east_1: "SAD Istok (Sjeverna Virdžinija)"
us_west_1: "SAD Zapad (Sjeverna Kalifornija)"
us_west_2: "SAD Zapad (Oregon)"
eu_west_1: "EU (Irska)"
eu_central_1: "EU (Frankfurt)"
ap_southeast_1: "Azija Pacifik (Singapur)"
ap_southeast_2: "Azija Pacifik (Sidnej)"
ap_south_1: "Azija Pacifik (Mumai)"
ap_northeast_1: "Azija Pacifik (Tokio)"
ap_northeast_2: "Azija Pacifik (Seul)"
sa_east_1: "Južna Amerika (Sao Paulo)"
cn_north_1: "Kina (Peking)"
edit: 'izmjeni naslov i kategoriju ove teme'
not_implemented: "That feature hasn't been implemented yet, sorry!"
no_value: "Ne"
@ -189,7 +209,7 @@ bs_BA:
like_count: "Broj Lajkova"
topic_count: "Broj Tema"
post_count: "Broj Postova"
user_count: "Broj Članova"
user_count: "Korisnici"
active_user_count: "Aktivnih korisnika"
contact: "Kontaktirajte nas"
contact_info: "U slučaju da forum ne radi, molimo kontaktirajte nas na %{contact_info}."
@ -233,6 +253,8 @@ bs_BA:
undo: "Nazad"
revert: "Vrati"
failed: "Neuspješno"
switch_to_anon: "Uđi u privatni modus"
switch_from_anon: "Izađi iz privatnog modusa"
banner:
close: "Dismiss this banner."
edit: "Uredite ovaj baner >>"
@ -319,7 +341,7 @@ bs_BA:
from: "Od"
to: "Za"
edit:
title: 'Edituj Grupu'
title: 'Preimenuj Grupu'
full_name: 'Puno ime'
add_members: "Dodaj Članove"
delete_member_confirm: "Ukloni '%{username}' iz '%{group}' grupe?"
@ -327,6 +349,14 @@ bs_BA:
title: "Zahtjev za članstvom"
body: "Želio bi da apliciram u članstvo @%{groupName}."
name_placeholder: "Ime grupe, bez razmaka, ista pravila kao za korisničko ime"
public: "Dozvolite korisnicima da se pridruže/napuste grupu slobodno (Zahtjeva da grupa bude vidljiva)"
empty:
posts: "Ne postoje postovi člana ove grupe."
members: "Nema članova u grupi."
mentions: "Nema spominjanja u grupi."
messages: "Nema novih poruka za ovu grupu."
topics: "Nema novih tema od strane članova ove grupe."
logs: "Nema novih logova za ovu grupu."
add: "Dodaj"
join: "Pridruži se grupi"
leave: "Napusti grupu"
@ -334,14 +364,22 @@ bs_BA:
automatic_group: Automatska grupa
closed_group: Zatvorena grupa
is_group_user: "Vi ste član ove grupe"
allow_membership_requests: "Dozvolite korisnicima da šalju zahtjeve za članstvom vlasnicima grupe (Zahtjeva da svako može @spomenuti grupu)"
membership: "Članstvo"
name: "Ime"
user_count: "Broj članova"
bio: "O grupi"
selector_placeholder: "Dodaj članove"
owner: "vlasnik"
visible: "Grupa je vidljiva svim korisnicima"
index:
title: "Grupe"
empty: "Vidljive grupe još ne postoje."
title:
one: "grupa"
few: "grupe"
other: "grupe"
activity: "Aktivnost"
members: "Članovi"
topics: "Teme"
posts: "Postovi"
@ -355,11 +393,15 @@ bs_BA:
members_mods_and_admins: "Samo članovi grupe, moderatori i admini"
everyone: "Svatko"
trust_levels:
title: "Razina povjerenja je automatski dodijeljena članovima kada su postavljeni: "
none: "Ništa"
notifications:
watching:
title: "Posmatram"
description: "Dobićete obavijest za svaki novi post u svakoj novoj poruci, i broj novih odgovora će biti prikazan."
watching_first_post:
title: "Prva objava"
description: "Bit će te obavješteni samo o prvim objavama u svakoj novoj temi ove grupe."
tracking:
title: "Praćenje"
description: "Bićete obaviješteni ukoliko neko spomene vaše @ime ili nešto što je naslovljeno za vas, i broj novih odgovora će biti prikazan."
@ -369,6 +411,15 @@ bs_BA:
muted:
title: "Utišano"
description: "Nećete biti obaviješteni zbog nove teme unutar ove grupe."
flair_url: "Slika Avatara sposobnosti"
flair_url_placeholder: "(Opciono) URL slike ili Font Awesome class"
flair_bg_color: "Boja pozadine Slike Avatara sposobnosti"
flair_bg_color_placeholder: "(Opciono) Hex broj boje"
flair_color: "Boja Avatara sposobnosti"
flair_color_placeholder: "(Opciono) Hex broj boje"
flair_preview_icon: "Preview ikona"
flair_preview_image: "Preview slika"
flair_note: "Obavještenje: Sposobnosti će biti prikazane samo za korisnike primarne grupe."
user_action_groups:
'1': "Dati Lajkovi"
'2': "Dobijeni Lajkovi"
@ -423,6 +474,11 @@ bs_BA:
profile: "Profil"
mute: "Mutiraj"
edit: "Uredi Postavke"
download_archive:
button_text: "Preuzmite svoju objavu"
confirm: "Da li ste sigurni da želite preuzeti svoju objavu?"
success: "Preuzimanje je započeto, bit će te obavješteni porukom kada proces bude završen."
rate_limit_error: "Objava može biti preuzeta samo jedanput na dan, molimo vas da pokušate sutra ponovo."
new_private_message: "Nova poruka"
private_message: "Privatne Poruke"
private_messages: "Poruke"
@ -444,7 +500,9 @@ bs_BA:
disable: "Isključi notifikacije"
enable: "Uključi notifikacije"
each_browser_note: "Napomena: Ovu opciju morate promjeniti na svakom pregledniku."
dismiss_notifications: "Odpusti sve"
dismiss_notifications_tooltip: "Markiraj sve nepročitane notifikacije kao pročitane"
first_notification: "Vaša prva obavijest! Selektirajte je kako bi započeli."
disable_jump_reply: "Don't jump to your new post after replying"
dynamic_favicon: "Show incoming message notifications on favicon (experimental)"
external_links_in_new_tab: "Open all external links in a new tab"
@ -458,9 +516,35 @@ bs_BA:
suspended_notice: "This user is suspended until {{date}}."
suspended_reason: "Reason: "
github_profile: "Github"
email_activity_summary: "Sažetak aktivnosti"
mailing_list_mode:
label: "Mejling lista mod"
enabled: "Uključite mod Mejling lista"
instructions: |
Ova Postavka nadvladava postavku Sažetak aktivnosti.<br />
Isključene teme (Muted topics) i kategorije nisu uključeni u ovim e-mailovima.
daily: "Šalji dnevne promjene."
individual: "Šalji e-mail za svaku novu objavu"
individual_no_echo: "Šalji e-mail za svaki novu objavu izuzev vlastite"
many_per_day: "Pošalji mi e-mail za svaku novu objavu (od prilike {{dailyEmailEstimate}} puta po danu)"
few_per_day: "Pošalji mi e-mail za svaku novu objavu (od prilike 2 puta po danu)"
tag_settings: "Tagovi"
watched_tags: "Gledano"
watched_tags_instructions: "Automatski će te gledati sve teme sa ovim tagom. Bit će te obavješteni o svim novim objavama i temama, i također broj novih objava će biti prikazan pored teme."
tracked_tags: "Praćeno"
tracked_tags_instructions: "Automatski će te pratiti sve teme sa ovim tagovima. Broj novih objava će se pojaviti pored teme."
muted_tags: "Isključen"
muted_tags_instructions: "Nećete biti obavješteni o novim temama sa ovim tagom, i neće biti prikazani u listi Novije."
watched_categories: "Watched"
watched_categories_instructions: "Automatski će te gledati sve teme u ovim kategorijama. Bit će te obavješteni o svim novim objavama i temama, i također broj novih objava će biti prikazan pored teme."
tracked_categories: "Tracked"
tracked_categories_instructions: "Automatski će te pratiti sve teme u ovim kategorijama. Broj novih objava će se pojaviti pored teme."
watched_first_post_categories: "Prva objava"
watched_first_post_categories_instructions: "Bit će te obavješteni samo o prvim objavama u svakoj novoj temi u ovim kategorijama."
watched_first_post_tags: "Prva objava"
watched_first_post_tags_instructions: "Bit će te obavješteni o prvoj objavi u svakoj novoj temi sa ovim tagovima."
muted_categories: "Muted"
muted_categories_instructions: "Nećete biti obavješteni o bilo čemu što se odnosi na nove teme u ovim kategorijama, i neće biti prikazani u listi Novije."
delete_account: "Delete My Account"
delete_account_confirm: "Are you sure you want to permanently delete your account? This action cannot be undone!"
deleted_yourself: "Your account has been deleted successfully."
@ -471,7 +555,12 @@ bs_BA:
muted_users: "Utišani"
muted_users_instructions: "Odbij sve notifikacije od ovih korisnika."
muted_topics_link: "Prikaži utišane teme"
watched_topics_link: "Prikaži gledane teme"
automatically_unpin_topics: "Automatski otkači temu kada dođem do dna"
apps: "Aplikacije"
revoke_access: "Oduzmi pristup"
undo_revoke_access: "Poništi oduzeti pristup"
api_approved: "Odobreno:"
staff_counters:
flags_given: "helpful flags"
flagged_posts: "flagged posts"
@ -500,6 +589,7 @@ bs_BA:
error: "Desila se greška prilikom promjene."
change_username:
title: "Change Username"
confirm: "Ukoliko promijenite vaše korisničko ime, sva dosadašnja citiranja u vašim objavama te @ime spomeni će biti ugašeni/sa vašim eventualno novim nickom razdvojeni. Da li ste APSOLUTNO SIGURNI da to želite učiniti?"
taken: "Sorry, that username is taken."
error: "There was an error changing your username."
invalid: "That username is invalid. It must only include numbers and letters"
@ -523,21 +613,25 @@ bs_BA:
change_profile_background:
title: "Pozadina profila"
instructions: "Pozadinske slike profila će biti centrirane i imati širinu od 850px."
change_card_background:
title: "Pozadina Korisničke kartice"
instructions: "Pozadinske slike će biti centrirane i imati standard širinu od 590 pixela."
email:
title: "Email"
instructions: "Nikada se ne pokazuje javno."
instructions: "Nikad ne pokazuje javno."
ok: "Izgleda dobro. Poslat ćemo email sa konfirmacijom."
invalid: "Molimo vas unesite validnu email adresu."
authenticated: "Your email has been authenticated by {{provider}}."
frequency_immediately: "Slati ćemo vam e-mail obavijesti odmah na novo, ukoliko niste pročitali sadržaj koji smo vam prvobitno e-mailom poslali."
name:
title: "Ime"
instructions: "Vaše puno ime."
instructions: "vaše puno ime (opciono)"
instructions_required: "Vaše puno ime"
too_short: "Vaše ime je prekratko."
ok: "Vaše ime izgleda ok."
username:
title: "Nadimak"
instructions: "Originalno, bez razmaka, kratko."
instructions: "unikatno, bez tipke praznog prostora, kratko"
short_instructions: "Ljudi vas mogu spomenuti preko @{{username}}."
available: "Vaš nadimak je dostupan."
global_match: "Email već postoji kao član foruma."
@ -552,6 +646,7 @@ bs_BA:
title: "Interface language"
instructions: "User interface language. It will change when you refresh the page."
default: "(default)"
any: "bilo koji"
password_confirmation:
title: "Šifra Opet"
last_posted: "Posljednji Odgovor"
@ -560,25 +655,34 @@ bs_BA:
created: "Registrovan"
log_out: "Izloguj se"
location: "Lokacija"
card_badge:
title: "Bedž Korisničke kartice"
website: "Sajt"
email_settings: "Email"
like_notification_frequency:
title: "Notifikuj ukoliko se nekome sviđa"
always: "Uvijek"
first_time_and_daily: "Prvi put kada je objava lajkana i svakodnevno"
first_time: "Prvi put kada je objava lajkana"
never: "Nikad"
email_previous_replies:
title: "Uključi predhodne odgovore na objave u dnu e-maila"
unless_emailed: "ukoliko nije već poslano"
always: "uvijek"
never: "nikad"
email_digests:
title: "Kada forum ne posjećujem, pošaljite mi e-mail sa Sažetkom popularnih tema i odgovora"
every_30_minutes: "svakih 30. min"
every_hour: "po satu"
daily: "dnevno"
every_three_days: "svaka tri dana"
weekly: "nedeljno"
every_two_weeks: "svake dvije sedmice"
include_tl0_in_digests: "Uključi i sadržaj od strane novih korisnika u e-mail Sažetku"
email_in_reply_to: "Uključi odlomake sa odgovorenih objava u e-mailovima"
email_direct: "Receive an email when someone quotes you, replies to your post, or mentions your @username"
email_private_messages: "Receive an email when someone sends you a private message"
email_always: "Pošalji mi e-mail obavijesti čak iako sam aktivan na forumu"
other_settings: "Other"
categories_settings: "Categories"
new_topic_duration:
@ -600,6 +704,7 @@ bs_BA:
after_4_minutes: "poslije 4 minute"
after_5_minutes: "poslije 5 minuta"
after_10_minutes: "poslije 10 minuta"
notification_level_when_replying: "Kada objavim objavu u temi, postavi tu temu u"
invited:
search: "kucaj da potražiš pozivnice..."
title: "Pozivnice"
@ -607,24 +712,33 @@ bs_BA:
sent: "poslano"
none: "Nema poziva na čekanju"
redeemed: "Redeemed Invites"
redeemed_tab: "Iskorišteno"
redeemed_tab_with_count: "Iskorišteno ({{count}})"
redeemed_at: "Redeemed"
pending: "Pending Invites"
pending_tab: "Na čekanju"
pending_tab_with_count: "Na čekanju ({{count}})"
topics_entered: "Topics Viewed"
posts_read_count: "Posts Read"
expired: "This invite has expired."
rescind: "Remove"
rescinded: "Invite removed"
reinvite: "Resend Invite"
reinvite_all: "Ponovo pošalji sve pozivnice"
reinvited: "Invite re-sent"
reinvited_all: "Sve pozivnice su ponovo poslate!"
time_read: "Read Time"
days_visited: "Days Visited"
account_age_days: "Account age in days"
create: "Pošalji Pozivnicu"
generate_link: "Kopiraj link za invite"
link_generated: "Link pozivnice je uspješno generisan!"
valid_for: "Link pozvinice je validan jedino za ovu e-mail adresu: %{email}"
bulk_invite:
none: "Još uvijek niste ovdje pozvali nikoga. Možete slati individualne pozivnice, ili pozvati mnogo ljudi od jednom koristeći se <a href='https://meta.discourse.org/t/send-bulk-invites/16468'>dizanjem CSV datoteke</a>."
text: "Bulk Invite from File"
success: "File uploaded successfully, you will be notified shortly with progress."
error: "Neuspješno, datoteka bi trebala biti u .csv formatu."
password:
title: "Šifra"
too_short: "Vaša šifra je prekratka."
@ -632,7 +746,7 @@ bs_BA:
same_as_username: "Vaš pasword je isti kao vaše korisničko ime."
same_as_email: "Vaš pasword je isti kao vaš email."
ok: "Vaša šifra izgleda ok."
instructions: "Barem %{count} karaktera."
instructions: "minimalno %{count} karaktera"
summary:
title: "Sumirano"
stats: "Statistike"
@ -643,6 +757,15 @@ bs_BA:
top_topics: "Top Teme"
no_topics: "Nema temi još"
more_topics: "Više temi"
top_badges: "Top bedževi"
no_badges: "Još uvijek nema bedževa."
more_badges: "Više bedževa"
top_links: "Top linkovi"
no_links: "Još uvijek nema linkova."
most_liked_by: "Najviše lajkano od"
most_liked_users: "Najviše lajkano"
most_replied_to_users: "Najviše odgovoreno ka"
no_likes: "Još uvijek nema lajkova."
associated_accounts: "Associated accounts"
ip_address:
title: "Zadnja IP Adresa"
@ -685,8 +808,18 @@ bs_BA:
logout: "Izlogovani ste."
refresh: "Osvježi"
read_only_mode:
enabled: "Ovaj sajt je u read only mod-u: Dozvoljeno je čitati. Možete nastaviti sa pregledom, ali odgovaranje na objave, lajkanje i ostale akcije su isključene za sada."
login_disabled: "Login is disabled while the site is in read only mode."
logout_disabled: "Odjava je isključena sve dok je sajt u read only tj. samo čitanje je dozvoljeno mod-u."
too_few_topics_and_posts_notice: "Odpočnimo <a href='http://blog.discourse.org/2014/08/building-a-discourse-community/'>sa diskusijom!</a> Trenutno postoje <strong>%{currentTopics} / %{requiredTopics}</strong> teme i <strong>%{currentPosts} / %{requiredPosts}</strong> objave. Novi posjetioci trebaju par novih diskusija za čitanje i shodne reakcije."
too_few_topics_notice: "Odpočnimo <a href='http://blog.discourse.org/2014/08/building-a-discourse-community/'>sa diskusijom!</a> Trenutno postoje <strong>%{currentTopics} / %{requiredTopics}</strong> teme. Novi posjetioci trebaju par novih diskusija za čitanje i shodne reakcije."
too_few_posts_notice: "Odpočnimo <a href='http://blog.discourse.org/2014/08/building-a-discourse-community/'>sa diskusijom!</a> Trenutno postoje <strong>%{currentPosts} / %{requiredPosts}</strong> objave. Novi posjetioci trebaju par novih diskusija za čitanje i shodne reakcije."
logs_error_rate_notice:
reached: "<b>%{relativeAge}</b> <a href='%{url}' target='_blank'>%{rate}</a> dosegnut postavljeni limit sajta od %{siteSettingRate}."
exceeded: "<b>%{relativeAge}</b> <a href='%{url}' target='_blank'>%{rate}</a> prelazi postavljeni limit sajta od %{siteSettingRate}."
learn_more: "learn more..."
all_time: 'ukupno'
all_time_desc: 'ukupno kreiranih tema'
year: 'godina'
year_desc: 'teme kreirane u zadnjih 365 dana'
month: 'mjesec'
@ -703,8 +836,13 @@ bs_BA:
sign_up: "Registruj se"
hide_session: "Podsjeti me sutra"
hide_forever: "ne hvala"
hidden_for_session: "OK, pitat ću vas opet sutra. Također možete u svako doba koristiti 'Loguj se' kako bi napravili nalog."
intro: "Hej tamo! :heart_eyes: Izgleda da uživaš u ovoj diskusiji, ali još uvijek nemaš prijavljen račun."
value_prop: "Kada osnujete nalog, mi pamtimo tačno što ste do sada čitali, tako da uvijek kada se vratite čekat će vas samo nepročitane teme, tačno tamo gdje ste prvobitno stali. Također dobijate i obavijesti, ovdje i preko e-maila, kad god su objavljene nove objave. Također možeš lajkat objave kako bi ste svijetu udijelili svoju velikodušnu ljubav. :heartbeat:"
summary:
enabled_description: "You're viewing a summary of this topic: the most interesting posts as determined by the community."
description: "Trenutno postoje <b>{{replyCount}}</b> odgovora."
description_time: "Trenutno postoje <b>{{replyCount}}</b> odgovora sa procijenjenim vremenom čitanja od <b>{{readingTime}} minuta</b>."
enable: 'Summarize This Topic'
disable: 'Show All Posts'
deleted_filter:
@ -716,6 +854,7 @@ bs_BA:
title: "Privatna Poruka"
invite: "Pozovi Druge..."
remove_allowed_user: "Do you really want to remove {{name}} from this private message?"
remove_allowed_group: "Da li zaista želite da uklonite {{name}} sa ove poruke?"
email: 'Email'
username: 'Ime'
last_seen: 'Viđen'
@ -724,6 +863,7 @@ bs_BA:
trust_level: 'Nivo Povjerenja'
search_hint: 'ime'
create_account:
disclaimer: "Registracijom, vi se slažete sa <a href='{{privacy_link}}'>policom o privatnosti</a> i <a href='{{tos_link}}'>uslovima korištenja servisa</a>."
title: "Kreiraj Nalog"
failed: "Something went wrong, perhaps this email is already registered, try the forgot password link"
forgot_password:
@ -755,6 +895,7 @@ bs_BA:
requires_invite: "Sorry, access to this forum is by invite only."
not_activated: "You can't log in yet. We previously sent an activation email to you at <b>{{sentTo}}</b>. Please follow the instructions in that email to activate your account."
not_allowed_from_ip_address: "You can't login from that IP address."
admin_not_allowed_from_ip_address: "Ne možete se logirati kao admin sa te IP adrese."
resend_activation_email: "Click here to send the activation email again."
sent_activation_email_again: "We sent another activation email to you at <b>{{currentEmail}}</b>. It might take a few minutes for it to arrive; be sure to check your spam folder."
to_continue: "Molimo vas ulogujte se"
@ -771,6 +912,7 @@ bs_BA:
message: "Identifikujemo se sa Twitterom (nadamo se da su vam isključeni popup blokeri)"
instagram:
title: "sa Instagramom"
message: "Prijava preko Instagrama (osigurajte da pop up blokeri budu isključeni)"
facebook:
title: "sa Facebook"
message: "Identifikujemo sa Facebook (nadamo se da su vam isključeni popup blokeri)"
@ -780,23 +922,46 @@ bs_BA:
github:
title: "sa GitHub"
message: "Authenticating with GitHub (make sure pop up blockers are not enabled)"
emoji_set:
apple_international: "Apple/International"
google: "Google"
twitter: "Twitter"
emoji_one: "Emoji One"
win10: "Win10"
category_page_style:
categories_only: "Samo kategorije"
categories_with_featured_topics: "Kategorije sa Izdvojenim temama"
categories_and_latest_topics: "Kategorije i Novije teme"
shortcut_modifier_key:
shift: 'Shift'
ctrl: 'Ctrl'
alt: 'Alt'
composer:
emoji: "Emotikoni :)"
more_emoji: "više..."
options: "Opcije"
whisper: "šapat"
unlist: "nelistan"
add_warning: "Ovo je zvanično upozorenje."
toggle_whisper: "Uključi kao Whisper"
toggle_unlisted: "Uključi kao nelistan"
posting_not_on_topic: "Na koju temu želite da odgovorite?"
saving_draft_tip: "čuvam"
saved_draft_tip: "sačuvano"
saved_local_draft_tip: "sačuvano lokalno"
similar_topics: "Tvoja tema je slična..."
drafts_offline: "offline sačuvano"
cannot_see_mention:
category: "Spomenuli ste {{username}} ali isti neće biti obavješteni zbog toga što nemaju pristup ovoj kategoriji. Morate ih dodati u Grupu koja ima pristup ka ovoj kategoriji."
private: "Spomenuli ste {{username}} ali isti neće biti obaviješteni zbog toga što nisu u mogućnosti da vide ovu personalnu poruku. Morate ih prvobitno pozvati u ovu PP tj. Personalnu poruku."
duplicate_link: "Izgleda da je vaš link ka <b>{{domain}}</b> već objavljen u temi od strane <b>@{{username}}</b> u <a href='{{post_url}}'>odgovoru {{ago}}</a> da li ste sigurni da želite isti ponovo objaviti?"
error:
title_missing: "Naslov je obavezan"
title_too_short: "Naslov mora biti najmanje {{min}} karaktera"
title_too_long: "Naslov ne može biti više od {{max}} karaktera"
post_missing: "Odgovor ne može biti prazan"
post_length: "Odgovor mora biti najmanje {{min}} karaktera"
try_like: 'Jeste li probali <i class="fa fa-heart"></i> dugme?'
category_missing: "Morate odabrati kategoriju"
save_edit: "Sačuvaj Izmene"
reply_original: "Odgovori na Originalnu Temu"
@ -808,8 +973,10 @@ bs_BA:
title: "Ili pritisni Ctrl+Enter"
users_placeholder: "Dodaj člana"
title_placeholder: "O čemu je ova diskusija u jednoj rečenici?"
title_or_link_placeholder: "Ukucajte naziv, ili zalijepite link ovdje"
edit_reason_placeholder: "zašto pravite izmjenu?"
show_edit_reason: "(dodaj razlog izmjene)"
topic_featured_link_placeholder: "Unesite link prikazan sa nazivom"
reply_placeholder: "Ovdje kucate vaš tekst. Koristite Markdown, BBcode ili HTML kako bi formatirali isti. Povucite ili zaljepite slike."
view_new_post: "Pogledaj svoj novi post."
saving: "Učitavam"
@ -831,6 +998,7 @@ bs_BA:
quote_text: "citat u bloku"
code_title: "Formatiran Tekst"
code_text: "indent preformatted text by 4 spaces"
paste_code_text: "ukucaj ili zalijepi kod ovdje"
upload_title: "Upload"
upload_description: "unesi opis uploada"
olist_title: "Numbered List"
@ -842,6 +1010,10 @@ bs_BA:
help: "Markdown Editing Help"
toggler: "sakrij ili pokaži komposer"
modal_cancel: "Otkaži"
cant_send_pm: "Neuspješno, ne možete slati poruke ka %{username}."
yourself_confirm:
title: "Da li ste zaboravili da dodate primaoca?"
body: "Trenutno ova poruka biješe poslana samo vama!"
admin_options_title: "Optional staff settings for this topic"
auto_close:
label: "Auto-close topic time:"
@ -855,6 +1027,7 @@ bs_BA:
notifications:
title: "obaviještenja na spomenuti @nadimak, odgovori na vaše teme i postove, privatne poruke, itd"
none: "Nemate obavijesti trenutno."
empty: "Nema obavještenja."
more: "pogledaj starija obaviještenja"
total_flagged: "ukupno opomenutih postova"
mentioned: "<i title='spomenut' class='icon'>@</i><p><span>{{username}}</span> {{description}}</p>"
@ -867,22 +1040,41 @@ bs_BA:
invitee_accepted: "<i title='prihvatio pozivnicu' class='fa fa-user'></i><p><span>{{username}}</span> accepted your invitation</p>"
moved_post: "<i title='pomjerio post' class='fa fa-sign-out'></i><p><span>{{username}}</span> moved {{description}}</p>"
granted_badge: "<i title='bedž dobijen' class='fa fa-certificate'></i><p>Zaslužen '{{description}}'</p>"
watching_first_post: "<i title='new topic' class='fa fa-dot-circle-o'></i><p><span>Nova Tema</span> {{description}}</p>"
alt:
mentioned: "Spomenut od"
quoted: "Citiran od"
replied: "Odgovoreno"
posted: "Post od"
edited: "Editujte vaš post"
liked: "Vole vaš post"
private_message: "Privatna poruka od"
invited_to_private_message: "Pozvani na privatnu poruku od "
invited_to_topic: "Pozvani na temu od"
invitee_accepted: "Pozivnica prihvaćena od"
moved_post: "Vaša objava je premještena od strane "
linked: "Link ka vašoj objavi"
granted_badge: "Bedž odobren"
group_message_summary: "Poruke u grupnom sandučetu"
popup:
mentioned: '{{username}} vas je spomenuo/la u "{{topic}}" - {{site_title}}'
group_mentioned: '{{username}} vas je spomenuo/la u "{{topic}}" - {{site_title}}'
quoted: '{{username}} vas je citirao/la u "{{topic}}" - {{site_title}}'
replied: '{{username}} vam je odgovorio/la u "{{topic}}" - {{site_title}}'
posted: '{{username}} je objavio/la "{{topic}}" - {{site_title}}'
private_message: '{{username}} vam je poslao/la privatnu poruku u "{{topic}}" - {{site_title}}'
linked: '{{username}} je linkao/la vašu objavu "{{topic}}" - {{site_title}}'
upload_selector:
title: "Dodaj sliku"
title_with_attachments: "Dodaj sliku ili fajl"
from_my_computer: "Sa mog uređaja"
from_the_web: "Sa neta"
remote_tip: "link do slike http://primjer.com/slika.jpg"
remote_tip_with_attachments: "link ka slici ili datoteci {{authorized_extensions}}"
local_tip: "Izaberi slike sa svog uređaja"
local_tip_with_attachments: "izaberite slike ili fajlove sa vašeg uređaja {{authorized_extensions}}"
hint: "(možete i mišom prenijeti vaše slike direktno iz vašeg foldera ovdje)"
hint_for_supported_browsers: "također možete povući i ispustiti ili zalijepiti slike u editor teksta"
uploading: "Uplodujem"
select_file: "Izaberi fajl"
image_link: "link do vaše slike će pokazivati"
@ -891,8 +1083,10 @@ bs_BA:
relevance: "Bitnost"
latest_post: "Zadnji postovi"
most_viewed: "Najviše pregledano"
most_liked: "Najviše lajkan"
select_all: "Izaberi sve"
clear_all: "Izbriši sve"
too_short: "Vaš termin za pretragu je prekratak."
title: "traži teme, postove, članove ili kategorije"
no_results: "Nema rezultata."
no_more_results: "Nema rezultata pretrage."
@ -900,16 +1094,65 @@ bs_BA:
post_format: "#{{post_number}} od {{username}}"
context:
user: "Traži postove od @{{username}}"
category: "Traži #{{category}} kategoriju"
topic: "Pretraži ovu temu"
private_messages: "Pretraži poruke"
advanced:
title: Napredna tražilica
posted_by:
label: Objavljeno od
in_category:
label: U kategoriji
in_group:
label: U grupi
with_badge:
label: Sa bedžom
with_tags:
label: Sa tagovima
filters:
label: Izlistaj samo teme/objave koje...
likes: Moji lajkovi
posted: Moje objave
watching: Pratim
tracking: Pratim
private: su u mojim porukama
bookmarks: Boji bookmark-ci
first: su friške prve objave
pinned: su okačene
unpinned: nisu okačene
wiki: su wiki
statuses:
label: Gdje teme
open: su otvorene
closed: su zatvorene
archived: su arhivirane
noreplies: imaju nula odgovora
single_user: sadrži jednog korisnika
post:
count:
label: Minimalan broj objava
time:
label: Objavljeno
before: prije
after: poslije
hamburger_menu: "idi ka drugoj temi, listi ili kategoriji"
new_item: "novo"
go_back: 'go back'
not_logged_in_user: 'user page with summary of current activity and preferences'
current_user: 'go to your user page'
topics:
new_messages_marker: "zadnja posjeta"
bulk:
select_all: "Označi sve"
clear_all: "Očisti sve"
unlist_topics: "Skini teme sa liste"
reset_read: "Reset Read"
delete: "Delete Topics"
dismiss: "Odbaci"
dismiss_read: "Odbaci sve nepročitane"
dismiss_button: "Odbaci..."
dismiss_tooltip: "Odbaci samo nove objave ili stopiraj praćenje tema"
also_dismiss_topics: "Prestani pratiti ove teme tako da se ubuduće za mene nikad ne prikazuju kao nepročitane "
dismiss_new: "Dismiss New"
toggle: "toggle bulk selection of topics"
actions: "Bulk Actions"
@ -918,6 +1161,9 @@ bs_BA:
archive_topics: "Archive Topics"
notification_level: "Change Notification Level"
choose_new_category: "Izaberi novu kategoriju za temu:"
change_tags: "Izmijeni tagove"
choose_new_tags: "Odaberi nove tagove za ove teme:"
changed_tags: "Tagovi ovih tema su izmijenjeni."
none:
unread: "Nemate više nepročitanih tema."
new: "Nemate više novih tema."
@ -925,9 +1171,13 @@ bs_BA:
posted: "Niste odgovorili ni na jednu temu."
latest: "Nema više novih tema. To je tužno."
hot: "Nema popularnih tema."
bookmarks: "Nemate još bookmark-iranih tema."
category: "Nema više tema u {{category}}."
top: "Nema više popularnih tema."
search: "Nema rezultata pretrage"
educate:
new: '<p>Vaše nove teme se ovdje pojavljuju.</p><p>Načelno, teme se smatraju novim i prikazivat će<span class="badge new-topic badge-notification" style="vertical-align:middle;line-height:inherit;">nova</span> indikator u slučaju da su objavljena u zadnja 2 dana.</p><p>Posjetite svoje <a href="%{userPrefsUrl}">postavke</a> ukoliko želite da to izmijenite.</p>'
unread: '<p>Vaše nepročitane teme se ovdje pojavljuju.</p><p>Načelno, teme su smatrane nepročitanim i prikazivat će brojač nepročitanih poruka<span class="badge new-posts badge-notification">1</span> ukoliko ste:</p><ul><li>Kreirali temu</li><li>Odgovorili na temu</li><li>Čitali temu duže od 4 minuta</li></ul><p>Ili ako ste explicitno označili temu za Praćenje ili Posmatrane preko kontrole obavještenja na dnu svake od tema.</p><p>Posjetite vaše <a href="%{userPrefsUrl}">postavke</a> ukoliko želite da to izmijenite.</p>'
bottom:
latest: "Nema više novih tema."
hot: "Nema više popularnih tema."
@ -937,10 +1187,21 @@ bs_BA:
unread: "Nema više nepročitanih tema."
category: "Nema više tema na kategoriji {{category}}."
top: "Nema više popularnih tema."
bookmarks: "Nema više bookmark-ovanih tema."
search: "Nema više rezultata pretrage."
topic:
unsubscribe:
stop_notifications: "Sad će te dobijati manje obavještenja za <strong>{{title}}</strong>"
change_notification_state: "Vaše trenutno stanje obavještenja je"
create: 'Započni Temu'
create_long: 'Započni novu Temu'
private_message: 'Započni privatnu konverzaciju'
archive_message:
help: 'Premjesti poruke u vašu arhivu'
title: 'Arhiva'
move_to_inbox:
title: 'Premjesti u Sanduče'
help: 'Premjesti poruke nazad u Sanduče'
list: 'Teme'
new: 'nova tema'
unread: 'nepročitana'
@ -973,16 +1234,27 @@ bs_BA:
auto_close_title: 'Auto-Close Settings'
auto_close_save: "Sačuvaj"
auto_close_remove: "Don't Auto-Close This Topic"
timeline:
back: "Nazad"
back_description: "Vratite se nazad na vašu zadnju nepročitanu objavu"
replies_short: "%{current} / %{total}"
progress:
title: progres teme
go_top: "vrh"
go_bottom: "dno"
go: "idi"
jump_bottom: "skoči na zadnju objavu"
jump_prompt: "skoči na..."
jump_prompt_of: "od %{count} objava"
jump_prompt_long: "Na koju objavu želite skočiti?"
jump_bottom_with_number: "skoči na post %{post_number}"
total: ukupan broj
current: trenutni post
notifications:
title: izmijenite učestalost dobijanja obavještenja o ovoj temi
reasons:
mailing_list_mode: "Imate uključenu mail listu, stoga će te biti obavještavani o odgovorima na ovu temu preko e-maila."
'3_10': 'Dobijat će te obavijesti jer pratite tag na ovoj temi.'
'3_6': 'Dobijat ćete notifikacije zato što motrite ovu temu.'
'3_5': 'Dobijat ćete notifikacije zato što motrite temu automatski.'
'3_2': 'Dobijat ćete notifikacije zato što pratite ovu temu.'
@ -999,12 +1271,16 @@ bs_BA:
'0': 'Ignorišete sve notifikacije u ovoj temi.'
watching_pm:
title: "Motrenje"
description: "Bit ćete obavješteni o svakom novom odgovoru u ovoj poruci, te će biti prikazan broj novih odgovora."
watching:
title: "Motrenje"
description: "Bit će te obavješteni o svakom novom odgovoru na ovu temu, te će biti prikazan broj novih odgovora."
tracking_pm:
title: "Praćenje"
description: "Broj novih odgovora će biti prikazan za ovu poruku. Bit će te obavješteni ukoliko neko pomene vaše @ime ili vam odgovori na poruku."
tracking:
title: "Praćenje"
description: "Broj novih odgovora će biti prikazan za ovu temu. Bit će te obavješteni ukoliko neko pomene vaše @ime ili vam odgovori na temu."
regular:
title: "Regularan"
description: "Dobiti ćete notifikaciju kada neko spomene tvoje @name ili odgovori na tvoj post."
@ -1016,6 +1292,7 @@ bs_BA:
description: "You will never be notified of anything about this private message."
muted:
title: "Mutirano"
description: "Nećete biti nikad obavješteni o bilo čemu sa ove teme, i neće biti prikazana u Novije"
actions:
recover: "Un-Delete Topic"
delete: "Delete Topic"
@ -1030,39 +1307,79 @@ bs_BA:
invisible: "Make Unlisted"
visible: "Make Listed"
reset_read: "Reset Read Data"
make_public: "Napiši temu javno"
make_private: "Napiši privatnu poruku"
feature:
pin: "Prikači temu"
unpin: "Otkači temu"
pin_globally: "Okači temu globalno"
make_banner: "Banner tema"
remove_banner: "Odstrani Banner temu"
reply:
title: 'Odgovori'
help: 'počni sa pisanjem odgovora na ovu temu'
post:
title: 'Odgovori'
topic:
title: 'Odgovori'
help: 'odpočni odgovor na ovu temu'
clear_pin:
title: "Clear pin"
help: "Clear the pinned status of this topic so it no longer appears at the top of your topic list"
share:
title: 'Sheruj'
help: 'podjeli link do ove teme'
print:
title: 'Print'
help: 'Otvori printersku verziju ove teme'
flag_topic:
title: 'Opomena'
help: 'anonimno prijavi ovu temu ili pošalji privatnu notifikaciju'
success_message: 'Uspješno ste opomenuli ovu temu.'
feature_topic:
title: "Istakni ovu temu."
pin: "Postavi ovu temu da se pojavljuje na vrhu {{categoryLink}} kategorije sve dok"
confirm_pin: "Već imate {{count}} okačenih tema. Previše okačenih tema može praviti teret za nove i anonimne korisnike. Da li ste sigurni da želite okačiti još jednu temu u ovoj kategoriji?"
unpin: "Uklonite ovu temu sa vrha {{categoryLink}} kategorije."
unpin_until: "Uklonite ovu temu sa vrha {{categoryLink}} kategorije ili sačekajte do <strong>%{until}</strong>."
pin_note: "Korisnici mogu sami individualno za sebe odkloniti okačku sa teme."
pin_validation: "Potreban je datum kako bi okačili ovu temu."
not_pinned: "Nema okačenih tema u {{categoryLink}}."
pin_globally: "Postavi ovu temu da se prikazuje na vrhu svih lista tema sve do"
confirm_pin_globally: "Već imate {{count}} globalno okačene teme. Previše okačenih tema mogu praviti teret za nove i anonimne korisnike. Da li ste sigurni da želite okačiti još jednu temu u ovoj kategoriji?"
unpin_globally: "Uklonite ovu temu sa vrha svih lista tema."
unpin_globally_until: "Odklonite ovu temu sa vrha svih lista tema ili sačekajte do <strong>%{until}</strong>."
global_pin_note: "Korisnici mogu sami individualno za sebe ukloniti okačku sa teme."
not_pinned_globally: "Nema tema okačenih globalno."
make_banner: "Postavi ovu temu kao banner koji se pojavljuje na vrhu svih stranica."
remove_banner: "Uklonite banner koji se pojavljuje u vrhu svih stranica."
banner_note: "Korisnici mogu odkloniti banner tako što će ga zatvoriti. U svakom momentu samo jedna tema može biti postavljena za banner."
no_banner_exists: "Nema banner tema."
banner_exists: "Trenutno <strong class='badge badge-notification unread'>postoji</strong> banner tema."
inviting: "Inviting..."
automatically_add_to_groups: "Ova pozivnica uključuje također i pristup ka sljedećim grupama:"
invite_private:
title: 'Invite to Private Message'
email_or_username: "Invitee's Email or Username"
email_or_username_placeholder: "email address or username"
action: "Invite"
success: "We've invited that user to participate in this private message."
success_group: "Pozvali ste čitavu tu grupu da učestvuje u raspavi u ovoj poruci."
error: "Sorry, there was an error inviting that user."
group_name: "group name"
controls: "Kontrole teme"
invite_reply:
title: 'Pozivnica'
username_placeholder: "korisničko ime"
action: 'Email pozivnica'
help: 'pošalji pozivnicu svojim prijateljima tako da i oni mogu odgovoriti na ovu temu. Bey registracije.'
to_forum: "We'll send a brief email allowing your friend to immediately join by clicking a link, no login required."
sso_enabled: "Unesite korisničko ime osobe koju želite da pozovete u ovu temu."
to_topic_blank: "Unesite korisničko ime ili e-mail adresu osobe koju želite da pozovete u ovu temu."
to_topic_email: "Unijeli ste e-mail adresu. Poslat ćemo e-mailom pozivnicu koja će omogućiti vašem prijatelju da odmah odgovori na ovu temu."
to_topic_username: "Unijeli ste korisničko ime. Na isto ćemo poslati obavještenje sa linkom pozivnice na ovu temu."
to_username: "Unesite korisničko ime osobe koju želite pozvati. Poslati ćemo obavještenje sa linkom pozivnice na ovu temu."
email_placeholder: 'name@example.com'
success_email: "Poslali smo e-mailom pozivnicu ka <b>{{emailOrUsername}}</b>. Obavjestiti ćemo vas kada pozivnica bude iskorištena. Provjerite tab pozivnica na vašoj profilnoj stranici kako bi ste upratili sve vaše pozivnice."
success_username: "Pozvali smo tog korisnika da prisustvuje u ovoj temi."
error: "Sorry, we couldn't invite that person. Perhaps they are already a user?"
login_reply: 'Uloguj se da odgovoriš'
filters:
@ -1108,6 +1425,7 @@ bs_BA:
edit: "Sorry, there was an error editing your post. Please try again."
upload: "Sorry, there was an error uploading that file. Please try again."
too_many_uploads: "Sorry, you can only upload one file at a time."
too_many_dragged_and_dropped_files: "Žao nam je, možete dizati samo 10 slika odjednom."
image_upload_not_allowed_for_new_user: "Sorry, new users can not upload images."
attachment_upload_not_allowed_for_new_user: "Sorry, new users can not upload attachments."
attachment_download_requires_login: "Sorry, you need to be logged in to download attachments."
@ -1329,6 +1647,8 @@ bs_BA:
top:
title: "Popularne"
help: "najaktivnije teme u zadnjih godinu, mjesec, sedmicu i dan"
all:
title: "Sve vrijeme"
yearly:
title: "Popularne Godišnje"
monthly:
@ -1337,12 +1657,15 @@ bs_BA:
title: "Popularne Sedmično"
daily:
title: "Popularne Dnevno"
all_time: "Sve vrijeme"
today: "Danas"
browser_update: 'Nažalost, vaš internet browser je prestar za ovaj korišćenje ovog foruma</a>. Idite na i <a href="http://browsehappy.com">obnovite vaš browser</a>.'
permission_types:
full: "Kreiraj / Odgovori / Vidi"
create_post: "Odgovori / Vidi"
readonly: "Vidi"
badges:
multiple_grant: "nagrađen više puta"
admin_js:
type_to_filter: "kucaj da sortiraš..."
admin:
@ -1462,6 +1785,9 @@ bs_BA:
info_html: "Your API key will allow you to create and update topics using JSON calls."
all_users: "All Users"
note_html: "Keep this key <strong>secret</strong>, all users that have it may create arbitrary posts as any user."
web_hooks:
events:
completion: "Vrijeme završetka"
plugins:
title: "Pluginovi"
installed: "Instalirani pluginovi"
@ -1957,11 +2283,31 @@ bs_BA:
with_time: <span class="username">%{username}</span> at <span class="time">%{time}</span>
emoji:
add: "Dodaj novi emoji"
embedding:
embed_whitelist_selector: "CSS selector za elemente koji su dozvoljeni u embeds"
embed_blacklist_selector: "CSS selector za elemente koji su odstranjeni sa embeds"
embed_classname_whitelist: "Dopuštena CSS class imena"
feed_polling_enabled: "Ubaci objave preko RSS/ATOM"
feed_polling_url: "URL ili RSS/ATOM feed za crawl"
save: "Sačuvaj Embedding postavke"
permalink:
title: "Permalink-ovi"
url: "URL"
topic_id: "ID teme"
topic_title: "Tema"
post_id: "ID objave"
post_title: "Objava"
category_id: "ID kategorije"
category_title: "Kategorija"
external_url: "Vanjski URL"
delete_confirm: Jeste li sigurni da želite izbrisati ovaj permalink?
form:
label: "Novo:"
add: "Dodaj"
filter: "Pretraga (URL ili vanjski URL)"
wizard_js:
wizard:
done: "Urađeno"
back: "Prethodno"
next: "Iduće"
step: "%{current} od %{total}"
@ -1974,6 +2320,7 @@ bs_BA:
other: "Vaša zajednica ima %{count} članova osoblja."
invites:
add_user: "Dodaj"
none_added: "Niste pozvali ni jednog admina/moderatora. Jeste li sigurni da želite nastaviti?"
roles:
admin: "Admin"
moderator: "Moderator"

View File

@ -154,6 +154,7 @@ cs:
enabled: 'uvedeno %{when}'
disabled: 'neuvedeno %{when}'
topic_admin_menu: "akce administrátora tématu"
wizard_required: "Je čas nastavit vaše fórum! <a href='%{url}' data-auto-route='true'>Spustit průvodce nastavením</a>!"
emails_are_disabled: "Všechny odchozí emaily byly administrátorem vypnuty. Žádné odchozí emaily nebudou odeslány."
bootstrap_mode_enabled: "Aby se váš web jednodušeji rozjel, nachází se v režimu bootstrap. Všichni noví uživatelé začínají s důveryhodností 1 a mají povolené denní odesílání souhrnných emailů. Tento režim se automaticky vypne, jakmile počet registrovaných uživatelů překročí %{min_users}."
bootstrap_mode_disabled: "Režim bootstrap bude deaktivován v následujících 24 hodinách."
@ -233,7 +234,7 @@ cs:
like_count: "Líbí se"
topic_count: "Témata"
post_count: "Příspěvky"
user_count: "Noví uživatelé"
user_count: "Uživatelé"
active_user_count: "Aktivní uživatelé"
contact: "Kontaktujte nás"
contact_info: "V případě kritické chyby nebo urgentní záležitosti ovlivňující tuto stránku nás prosím kontaktujte na %{contact_info}."
@ -346,6 +347,11 @@ cs:
one: "1 uživatel"
few: "%{count} uživatelé"
other: "%{count} uživatelů"
group_histories:
actions:
change_group_setting: "Změnit nastavení skupiny"
add_user_to_group: "Přidat uživatele"
remove_user_from_group: "Odebrat uživatele"
groups:
add: "Přidat"
selector_placeholder: "Přidat členy"
@ -472,6 +478,7 @@ cs:
each_browser_note: "Poznámka: Musíš změnit tuto volbu v každém prohlížeči, který používáš."
dismiss_notifications: "Odbýt vše"
dismiss_notifications_tooltip: "Označit všechny nepřečtené notifikace jako přečtené"
first_notification: "Vaše první notifikace! Klikněte zde a začněte."
disable_jump_reply: "Po odpovědi nepřeskakovat na nový příspěvek"
dynamic_favicon: "Zobrazit počet nových témat v ikoně prohlížeče"
external_links_in_new_tab: "Otevírat všechny externí odkazy do nové záložky"
@ -977,6 +984,7 @@ cs:
title: "Nebo zmáčkněte Ctrl+Enter"
users_placeholder: "Přidat uživatele"
title_placeholder: "O čem je ve zkratce tato diskuze?"
title_or_link_placeholder: "Sem vložte název téma"
edit_reason_placeholder: "proč byla nutná úprava?"
show_edit_reason: "(přidat důvod úpravy)"
reply_placeholder: "Piš tady. Pro formátování používej Markdown, BBCode nebo HTML. Přetáhni nebo vlož obrázky."
@ -1371,11 +1379,8 @@ cs:
make_banner: "Banner Topic"
remove_banner: "Remove Banner Topic"
reply:
post:
title: 'Odpovědět'
topic:
title: 'Odpovědět'
help: 'začněte psát odpověď na toto téma'
title: 'Odpovědět'
help: 'začněte psát odpověď na toto téma'
clear_pin:
title: "Odstranit připnutí"
help: "Odebere připnutí tohoto tématu, takže se již nebude zobrazovat na vrcholu seznamu témat"

View File

@ -1276,11 +1276,8 @@ da:
make_banner: "Gør emnet til en banner"
remove_banner: "Emnet skal ikke være banner længere"
reply:
post:
title: 'Svar'
topic:
title: 'Svar'
help: 'begynd at skrive et svar til dette emne'
title: 'Svar'
help: 'begynd at skrive et svar til dette emne'
clear_pin:
title: "Fjern tegnestift"
help: "Fjern tegnestiften på dette emne så det ikke længere vises i toppen af emnelisten"

View File

@ -214,7 +214,7 @@ de:
like_count: "Likes"
topic_count: "Themen"
post_count: "Beiträge"
user_count: "Neue Benutzer"
user_count: "Benutzer"
active_user_count: "Aktive Benutzer"
contact: "Kontaktiere uns"
contact_info: "Im Falle eines kritischen Problems oder einer dringenden Sache, die diese Website betreffen, kontaktiere uns bitte unter %{contact_info}."
@ -1407,7 +1407,6 @@ de:
title: 'Antworten'
topic:
title: 'Antworten'
help: 'beginne damit eine Antwort auf dieses Thema zu verfassen'
clear_pin:
title: "Loslösen"
help: "Dieses Thema von der Themenliste loslösen, sodass es nicht mehr am Anfang der Liste steht."
@ -1533,6 +1532,7 @@ de:
edit: "Du bearbeitest {{link}} {{replyAvatar}} {{username}}"
edit_reason: "Grund: "
post_number: "Beitrag {{number}}"
wiki_last_edited_on: "Wiki zuletzt bearbeitet am"
last_edited_on: "Beitrag zuletzt bearbeitet am"
reply_as_new_topic: "Mit verknüpftem Thema antworten"
continue_discussion: "Fortsetzung der Diskussion von {{postLink}}:"
@ -2678,7 +2678,7 @@ de:
revoke_admin: "Administration entziehen"
grant_moderation: "Moderation gewähren"
revoke_moderation: "Moderation entziehen"
backup_operation: "Backup läuft"
backup_create: "Backup erstellen"
deleted_tag: "Schlagwort gelöscht"
renamed_tag: "Schlagwort umbenannt"
revoke_email: "E-Mail widerrufen"
@ -2687,6 +2687,7 @@ de:
activate_user: "Benutzer aktivieren"
deactivate_user: "Benutzer deaktivieren"
change_readonly_mode: "Nur-Lesen-Modus ändern"
backup_download: "Backup herunterladen"
screened_emails:
title: "Gefilterte E-Mails"
description: "Wenn jemand ein Konto erstellt, werden die folgenden E-Mail-Adressen überprüft und es wird die Anmeldung blockiert oder eine andere Aktion ausgeführt."

View File

@ -655,6 +655,8 @@ en:
error: "(error)"
action: "Send Password Reset Email"
set_password: "Set Password"
choose_new: "Choose a new password"
choose: "Choose a password"
change_about:
title: "Change About Me"
@ -1041,6 +1043,7 @@ en:
to_continue: "Please Log In"
preferences: "You need to be logged in to change your user preferences."
forgot: "I don't recall my account details"
not_approved: "Your account hasn't been approved yet. You will be notified by email when you are ready to log in."
google:
title: "with Google"
message: "Authenticating with Google (make sure pop up blockers are not enabled)"
@ -1063,6 +1066,9 @@ en:
title: "with GitHub"
message: "Authenticating with GitHub (make sure pop up blockers are not enabled)"
password_reset:
continue: "Continue to %{site_name}"
emoji_set:
apple_international: "Apple/International"
google: "Google"
@ -1554,12 +1560,8 @@ en:
remove_banner: "Remove Banner Topic"
reply:
post:
title: 'Reply'
# help i.e. tooltop is at controls.reply
topic:
title: 'Reply'
help: 'begin composing a reply to this topic'
title: 'Reply'
help: 'begin composing a reply to this topic'
clear_pin:
title: "Clear pin"
@ -1707,6 +1709,7 @@ en:
wiki_last_edited_on: "wiki last edited on"
last_edited_on: "post last edited on"
reply_as_new_topic: "Reply as linked Topic"
reply_as_new_private_message: "Reply as new message to the same recipients"
continue_discussion: "Continuing the discussion from {{postLink}}:"
follow_quote: "go to the quoted post"
show_full: "Show Full Post"
@ -1892,7 +1895,8 @@ en:
hide: "Hide revision"
show: "Show revision"
revert: "Revert to this revision"
edit_wiki: "Edit wiki"
edit_wiki: "Edit Wiki"
edit_post: "Edit Post"
comparing_previous_to_current_out_of_total: "<strong>{{previous}}</strong> <i class='fa fa-arrows-h'></i> <strong>{{current}}</strong> / {{total}}"
displays:
inline:

View File

@ -214,7 +214,7 @@ es:
like_count: "Me gusta"
topic_count: "Temas"
post_count: "Posts"
user_count: "Usuarios nuevos"
user_count: "Usuarios"
active_user_count: "Usuarios activos"
contact: "Contáctanos"
contact_info: "En caso de un error crítico o un asunto urgente referente a este sitio, por favor, contáctanos en %{contact_info}."
@ -1404,10 +1404,10 @@ es:
remove_banner: "Remover tema de encabezado"
reply:
post:
title: 'Responder'
title: 'Respuesta'
topic:
title: 'Responder'
help: 'comienza a escribir una respuesta a este tema'
title: 'Respuesta'
help: 'empieza a escribir una respuesta a este tema'
clear_pin:
title: "Eliminar Destacado"
help: "Elimina el estado 'Destacado' de este tema para que no aparezca más en lo más alto de tu lista de temas"
@ -1580,7 +1580,7 @@ es:
via_auto_generated_email: "este post llegó a través de un email generado automáticamente"
whisper: "esto post es un susurro privado para moderadores"
wiki:
about: "este post es tipo wiki"
about: "este es un tema de tipo wiki"
archetypes:
save: 'Guardar opciones'
few_likes_left: "¡Gracias por compartir tu afecto! Te quedan solo unos pocos me gusta para hoy."
@ -1707,17 +1707,18 @@ es:
hide: "Ocultar revisión."
show: "Mostrar revisión."
revert: "Volver a esta revisión"
edit_wiki: "Editar wiki"
comparing_previous_to_current_out_of_total: "<strong>{{previous}}</strong> <i class='fa fa-arrows-h'></i> <strong>{{current}}</strong> / {{total}}"
displays:
inline:
title: "Muestra la producción asistida con adiciones y eleminaciones en línea"
button: '<i class="fa fa-square-o"></i> HTML'
button: 'HTML'
side_by_side:
title: "Mostrar la producción asistida estas de lado a lado"
button: '<i class="fa fa-columns"></i> HTML'
button: 'HTML'
side_by_side_markdown:
title: "Mostrar las diferencias crudas a la par"
button: '<i class="fa fa-columns"></i> Crudo'
button: 'Fuente'
category:
can: 'puede&hellip; '
none: '(sin categoría)'

View File

@ -1401,11 +1401,8 @@ et:
make_banner: "Tee teema bänneriks"
remove_banner: "Eemalda teema bännerist"
reply:
post:
title: 'vasta'
topic:
title: 'vasta'
help: 'alusta selle teema vastuse koostamist'
title: 'vasta'
help: 'alusta selle teema vastuse koostamist'
clear_pin:
title: "Kustuta esiletõstmine"
help: "Eemalda sellelt teemalt esiletõstetu staatus nii, et ta enam ei ilmuks teemade loetelu tipus"

View File

@ -214,7 +214,7 @@ fi:
like_count: "Tykkäyksiä"
topic_count: "Ketjuja"
post_count: "Viestejä"
user_count: "Uusia käyttäjiä"
user_count: "Käyttäjät"
active_user_count: "Aktiivisia käyttäjiä"
contact: "Yhteystiedot"
contact_info: "Sivustoon liittyvissä kiireellisissä asioissa, ota yhteyttä osoitteeseen %{contact_info}."
@ -1408,7 +1408,7 @@ fi:
title: 'Vastaa'
topic:
title: 'Vastaa'
help: 'aloita kirjottamaan uutta vastausta tähän ketjuun'
help: 'aloita kirjoittamaan vastausta tähän ketjuun'
clear_pin:
title: "Poista kiinnitys"
help: "Poista kiinnitys, jotta ketju ei enää pysy listauksen ylimpänä"
@ -1581,7 +1581,7 @@ fi:
via_auto_generated_email: "tämä viesti saapui automaattisesti generoituna sähköpostina"
whisper: "tämä viesti on yksityinen kuiskaus valvojille"
wiki:
about: "tämä viesti on wiki"
about: "tämä viesti on wiki-viesti"
archetypes:
save: 'Tallennusasetukset'
few_likes_left: "Kiitos hyvän mielen levittämisestä! Sinulla on enää muutama tykkäys jäljellä tälle päivälle."
@ -1708,17 +1708,18 @@ fi:
hide: "Piilota revisio"
show: "Näytä revisio"
revert: "Palaa tähän revisioon"
edit_wiki: "Muokkaa wikiä"
comparing_previous_to_current_out_of_total: "<strong>{{previous}}</strong> <i class='fa fa-arrows-h'></i> <strong>{{current}}</strong> / {{total}}"
displays:
inline:
title: "Näytä lisäykset ja poistot tekstin osana"
button: '<i class="fa fa-square-o"></i> HTML'
button: 'HTML'
side_by_side:
title: "Näytä muokkauksen versiot vierekkäin"
button: '<i class="fa fa-columns"></i> HTML'
button: 'HTML'
side_by_side_markdown:
title: "Näytä viestien lähdekoodit vierekkäin"
button: '<i class="fa fa-columns"></i> Teksti'
button: 'Raaka'
category:
can: 'voivat&hellip; '
none: '(ei aluetta)'
@ -1761,7 +1762,7 @@ fi:
change_in_category_topic: "Muokkaa kuvausta"
already_used: 'Tämä väri on jo käytössä toisella alueella'
security: "Turvallisuus"
special_warning: "Varoitus: Tämä alue on esituotettu ja sen turvallisuusasetuksia ei voi muuttaa. Jos et halua käyttää sitä, poista se sen sijaan."
special_warning: "Varoitus: Tämä on valmiiksi luotu alue, ja sen turvallisuusasetuksia ei voi muuttaa. Jos et näe käyttöä alueelle, älä muuta sen tarkoitusta vaan poista se."
images: "Kuvat"
auto_close_label: "Sulje ketjut automaattisesti tämän ajan jälkeen:"
auto_close_units: "tuntia"
@ -2623,12 +2624,17 @@ fi:
revoke_admin: "peru ylläpitäjän oikeudet"
grant_moderation: "myönnä valvojan oikeudet"
revoke_moderation: "peru valvojan oikeudet"
backup_operation: "varmuuskopiointi"
backup_create: "luo varmuuskopio"
deleted_tag: "poistettu tunniste"
renamed_tag: "uudelleen nimetty tunniste"
revoke_email: "peru sähköpostiosoite"
lock_trust_level: "lukitse luottamustaso"
unlock_trust_level: "poista luottamustason lukitus"
activate_user: "aktivoi käyttäjä"
deactivate_user: "poista käyttäjätili käytöstä"
change_readonly_mode: "muuta vain luku -tilaa"
backup_download: "lataa varmuuskopio"
backup_destroy: "tuhoa varmuuskopio"
screened_emails:
title: "Seulottavat sähköpostiosoitteet"
description: "Uuden käyttäjätunnuksen luonnin yhteydessä annettua sähköpostiosoitetta verrataan alla olevaan listaan ja tarvittaessa tunnuksen luonti joko estetään tai suoritetaan muita toimenpiteitä."

View File

@ -214,7 +214,7 @@ fr:
like_count: "J'aime"
topic_count: "Sujets"
post_count: "Nombre de messages"
user_count: "Nouveaux utilisateurs"
user_count: "Utilisateurs"
active_user_count: "Utilisateurs actifs"
contact: "Nous contacter"
contact_info: "En cas de problème critique ou urgent sur ce site, veuillez nous contacter : %{contact_info}"
@ -1707,17 +1707,18 @@ fr:
hide: "Masquer la révision"
show: "Afficher la révision"
revert: "Revenir à cette révision"
edit_wiki: "Modifier le wiki"
comparing_previous_to_current_out_of_total: "<strong>{{previous}}</strong> <i class='fa fa-arrows-h'></i> <strong>{{current}}</strong> / {{total}}"
displays:
inline:
title: "Afficher le rendu avec les ajouts et les retraits en ligne"
button: '<i class="fa fa-square-o"></i> HTML'
button: 'HTML'
side_by_side:
title: "Afficher les différences de rendu côte-à-côte"
button: '<i class="fa fa-columns"></i> HTML'
button: 'HTML'
side_by_side_markdown:
title: "Afficher les différences de la source côte-à-côte"
button: '<i class="fa fa-columns"></i> Brut'
button: 'Brut'
category:
can: 'peut&hellip; '
none: '(aucune catégorie)'

View File

@ -1145,11 +1145,8 @@ gl:
make_banner: "Tema do báner"
remove_banner: "Eliminar o tema do báner"
reply:
post:
title: 'Responder'
topic:
title: 'Responder'
help: 'responder a este tema'
title: 'Responder'
help: 'responder a este tema'
clear_pin:
title: "Borrar o estado Pegar"
help: "Borra o estado Pegado deste tema para que non apareza na banda superior da lista de temas."

View File

@ -214,7 +214,7 @@ he:
like_count: "לייקים"
topic_count: "נושאים"
post_count: "פוסטים"
user_count: "חדשים"
user_count: "משתמשים"
active_user_count: "משתמשים פעילים"
contact: "צרו קשר"
contact_info: "במקרה של ארוע קריטי או דחוף המשפיע על האתר, אנא צרו איתנו קשר ב: %{contact_info}."
@ -1409,7 +1409,7 @@ he:
title: 'תגובה'
topic:
title: 'תגובה'
help: 'התחילו לכתוב תגובה לנושא זה'
help: 'התחילו לחבר תגובה לנושא זה'
clear_pin:
title: "נקה נעיצה"
help: "נקה סטטוס נעוץ של נושא זה כדי שהוא לא יופיע עוד בראש רשימת הנושאים שלכם"
@ -1582,7 +1582,7 @@ he:
via_auto_generated_email: "פוסט זה הגיע דרך מייל שנוצר אוטומטית"
whisper: "פוסט זה הוא לחישה פרטית למנחים"
wiki:
about: "פוסט זה הוא ויקי"
about: "הפוסט הוא ויקי"
archetypes:
save: 'שמור אפשרויות'
few_likes_left: "תודה שאתם מפזרים אהבה! נותרו לכם מעט לייקים להיום."
@ -1709,17 +1709,18 @@ he:
hide: "הסתרת שינויים"
show: "הצגת שינויים"
revert: "חזרה לגרסה זו"
edit_wiki: "עריכת ויקי"
comparing_previous_to_current_out_of_total: "<strong>{{previous}}</strong> <i class='fa fa-arrows-h'></i> <strong>{{current}}</strong> / {{total}}"
displays:
inline:
title: "הצג את הפלט עם תוספות והסרות בתוכו"
button: '<i class="fa fa-square-o"></i> HTML'
button: 'HTML'
side_by_side:
title: "הצג את הפרשי הפלט אחד ליד השני"
button: '<i class="fa fa-columns"></i> HTML'
button: 'HTML'
side_by_side_markdown:
title: "הציגו את ההבדלי המקור הגולמיים זה לצד זה"
button: '<i class="fa fa-columns"></i> גלם'
button: 'גולמי'
category:
can: 'יכול&hellip; '
none: '(ללא קטגוריה)'

View File

@ -214,7 +214,7 @@ it:
like_count: "Mi piace"
topic_count: "Argomenti"
post_count: "Messaggi"
user_count: "Nuovi Utenti"
user_count: "Utenti"
active_user_count: "Utenti Attivi"
contact: "Contattaci"
contact_info: "Nel caso di un problema grave o urgente riguardante il sito, per favore contattaci all'indirizzo %{contact_info}."
@ -409,11 +409,15 @@ it:
muted:
title: "Silenziato"
description: "Non verrai mai avvertito per i nuovi argomenti in questo gruppo."
flair_url: "Immagine Avatar Flair"
flair_url_placeholder: "(Facoltativo) URL Immagine o classe Font Awesome"
flair_bg_color: "Colore di background Avatar Flair"
flair_bg_color_placeholder: "(Facoltativo) Codice esadecimale del colore"
flair_color: "Colore Avatar Flair"
flair_color_placeholder: "(Facoltativo) Codice esadecimale del colore"
flair_preview_icon: "Anteprima Icona"
flair_preview_image: "Anteprima Immagine"
flair_note: "Nota: Flair sarà mostrato solo per i primary group dell'utente."
user_action_groups:
'1': "Mi piace - Assegnati"
'2': "Mi piace - Ricevuti"
@ -619,7 +623,7 @@ it:
instructions: "Le immagini di sfondo saranno centrate e per difetto avranno un'ampiezza di 590px."
email:
title: "Email"
instructions: "Mai mostrato pubblicamente"
instructions: "mai mostrare al pubblico"
ok: "Ti invieremo una email di conferma"
invalid: "Inserisci un indirizzo email valido"
authenticated: "{{provider}} ha autenticato la tua email"
@ -629,13 +633,13 @@ it:
other: "Ti invieremo una email solo se non ti si vede da almeno {{count}} minuti."
name:
title: "Nome"
instructions: "Nome completo (facoltativo)"
instructions: "il tuo nome completo (opzionale)"
instructions_required: "Il tuo nome completo"
too_short: "Il nome è troppo breve"
ok: "Il nome sembra adeguato"
username:
title: "Nome utente"
instructions: "Deve essere univoco, senza spazi e breve"
instructions: "deve essere unico, senza spazi e breve"
short_instructions: "Gli utenti possono citarti scrivendo @{{username}}"
available: "Il nome utente è disponibile"
global_match: "L'email corrisponde al nome utente registrato"
@ -745,6 +749,7 @@ it:
none: "Non hai ancora invitato nessuno. Puoi invitare persone singole, o più persone insieme <a href='https://meta.discourse.org/t/send-bulk-invites/16468'>caricando un file CSV</a>."
text: "Invito di Massa da File"
success: "Il file è stato caricato con successo, riceverai un messaggio di notifica quando il processo sarà completato."
error: "Spiacenti, il file dovrebbe essere in formato CSV."
password:
title: "Password"
too_short: "La password è troppo breve."
@ -752,7 +757,7 @@ it:
same_as_username: "La tua password è uguale al tuo nome utente."
same_as_email: "La password coincide con l'email."
ok: "La password è adeguata"
instructions: "Minimo %{count} caratteri."
instructions: "Minimo %{count} caratteri"
summary:
title: "Riepilogo"
stats: "Statistiche"
@ -1397,11 +1402,8 @@ it:
make_banner: "Argomento Annuncio"
remove_banner: "Rimuovi Argomento Annuncio"
reply:
post:
title: 'Rispondi'
topic:
title: 'Rispondi'
help: 'inizia a scrivere una risposta a questo argomento'
title: 'Rispondi'
help: 'inizia a scrivere una risposta a questo argomento'
clear_pin:
title: "Spunta"
help: "Rimuovi la spunta da questo argomento, così non comparirà più in cima alla lista degli argomenti"
@ -2331,6 +2333,7 @@ it:
individual_event: "Seleziona eventi singoli."
verify_certificate: "Verifica il certificato TLS della URL payload"
active: "Attivo"
groups_filter: "Gruppi triggered"
delete_confirm: "Eliminare questo webhook?"
topic_event:
name: "Evento Argomento"
@ -2843,6 +2846,7 @@ it:
deactivate_explanation: "Un utente disattivato deve riconvalidare la propria email."
suspended_explanation: "Un utente sospeso non può connettersi."
block_explanation: "Un utente bloccato non può pubblicare messaggi o iniziare argomenti."
staged_explanation: "Un utente staged può solo postare via email in specifici topic."
bounce_score_explanation:
none: "L'indirizzo email non ha causato nessun errore di ritorno recentemente."
some: "Sono stati ricevuti alcuni errori di ritorno per quell'indirizzo email."

View File

@ -1110,11 +1110,8 @@ ja:
make_banner: "バナートピック"
remove_banner: "バナートピックを削除"
reply:
post:
title: '返信'
topic:
title: '返信'
help: 'このトピックに返信する'
title: '返信'
help: 'このトピックに返信する'
clear_pin:
title: "ピンを解除する"
help: "このトピックのピンを外し、トピックリストの先頭に表示されないようにする"

View File

@ -1151,11 +1151,8 @@ ko:
make_banner: "배너 주제"
remove_banner: "배너 주제 제거"
reply:
post:
title: '답글'
topic:
title: '답글'
help: '이 주제에 대한 답글 작성 시작'
title: '답글'
help: '이 주제에 대한 답글 작성 시작'
clear_pin:
title: "고정 취소"
help: "더 이상 목록의 맨 위에 표시하지 않도록 이 주제의 고정 상태를 해제합니다."

View File

@ -214,7 +214,7 @@ nb_NO:
like_count: "Likes"
topic_count: "Emner"
post_count: "Innlegg"
user_count: "Nye brukere"
user_count: "Brukere"
active_user_count: "Aktive brukere"
contact: "Kontakt oss"
contact_info: "I tilfelle en kritisk hendelse skulle inntreffe eller det er en hastesak som påvirker siden, ta kontakt på %{contact_info}."
@ -244,11 +244,11 @@ nb_NO:
preview: "forhåndsvisning"
cancel: "avbryt"
save: "Lagre endringer"
saving: "Lagrer..."
saving: "Lagrer"
saved: "Lagret!"
upload: "Last opp"
uploading: "Laster opp..."
uploading_filename: "Laster opp {{filename}}..."
uploading: "Laster opp"
uploading_filename: "Laster opp {{filename}}"
uploaded: "Lastet opp!"
enable: "Aktiver"
disable: "Deaktiver"
@ -623,7 +623,7 @@ nb_NO:
instructions: "Bakgrunnsbilder vil bli sentrert og ha en forvalgt bredde på 590 piksler."
email:
title: "E-post"
instructions: "Blir aldri vist offentlig"
instructions: "aldri vist til offentligheten"
ok: "Vi sender deg en e-post for å bekrefte"
invalid: "Oppgi en gyldig e-postadresse"
authenticated: "Din e-post har blitt autentisert av {{provider}}"
@ -633,13 +633,13 @@ nb_NO:
other: "Vi sender deg bare e-post hvis vi ikke har sett deg de siste {{count}} minuttene."
name:
title: "Navn"
instructions: "Ditt fulle navn (valgfritt)"
instructions: "ditt fulle navn (valgfritt)"
instructions_required: "Ditt fulle navn"
too_short: "Navnet ditt er for kort."
ok: "Navnet ditt ser bra ut."
username:
title: "Brukernavn"
instructions: "Unikt, kort og uten mellomrom."
instructions: "unikt, ingen mellomrom, kort"
short_instructions: "Folk kan nevne deg som @{{username}}."
available: "Ditt brukernavn er tilgjengelig."
global_match: "E-post stemmer med det registrerte brukernavnet"
@ -647,7 +647,7 @@ nb_NO:
not_available: "Ikke tilgjengelig. Prøv {{suggestion}}?"
too_short: "Ditt brukernavn er for kort."
too_long: "Ditt brukernavn er for langt."
checking: "Sjekker brukernavnets tilgjengelighet..."
checking: "Sjekker brukernavnets tilgjengelighet"
enter_email: 'Brukernavn funnet; oppgi samsvarende e-post'
prefilled: "E-post stemmer med dette registrerte brukernavnet"
locale:
@ -714,7 +714,7 @@ nb_NO:
after_10_minutes: "etter 10 minutt"
notification_level_when_replying: "Når jeg publiserer noe i et emner, sett det emnet til"
invited:
search: "skriv for å søke etter invitasjoner..."
search: "skriv for å søke etter invitasjoner"
title: "invitasjoner"
user: "Invitert bruker"
sent: "Sendt"
@ -757,7 +757,7 @@ nb_NO:
same_as_username: "Ditt passord er det samme som ditt brukernavn."
same_as_email: "Ditt passord er det samme som din e-post."
ok: "Passordet ditt ser bra ut"
instructions: "Minst %{count} tegn."
instructions: "minst %{count} tegn"
summary:
title: "Oppsummering"
stats: "Statistikk"
@ -815,7 +815,7 @@ nb_NO:
sent_by: "Sendt av"
private_message: "melding"
the_topic: "emnet"
loading: "Laster..."
loading: "Laster"
errors:
prev_page: "ved lasting"
reasons:
@ -852,7 +852,7 @@ nb_NO:
rate:
one: "1 feil/%{duration}"
other: "%{count} feil/%{duration}"
learn_more: "lær mer..."
learn_more: "lær mer"
all_time: 'totalt'
all_time_desc: 'totalt antall emner opprettet'
year: 'år'
@ -890,7 +890,7 @@ nb_NO:
disable: "Vis slettede innlegg"
private_message_info:
title: "Send"
invite: "Invitér andre..."
invite: "Inviter andre…"
remove_allowed_user: "Er du sikker på at du vil fjerne {{name}} fra denne meldingen?"
remove_allowed_group: "Vil du virkelig fjerne {{name}} fra denne meldingen?"
email: 'E-post'
@ -925,9 +925,9 @@ nb_NO:
rate_limit: "Vent litt før du logger inn igjen."
blank_username_or_password: "Oppgi din e-postadresse eller brukernavn og ditt passord."
reset_password: 'Nullstill passord'
logging_in: "Logger på..."
logging_in: "Logger på"
or: "Eller"
authenticating: "Autentiserer..."
authenticating: "Autentiserer"
awaiting_confirmation: "Din konto avventer aktivering. Bruk lenken for glemt passord for å sende en ny e-post for aktivering."
awaiting_approval: "Din konto har ikke blitt godkjent av en moderator ennå. Du vil motta en e-post når den er godkjent."
requires_invite: "Beklager, tilgang til dette forumet kun ved invitasjon."
@ -976,7 +976,7 @@ nb_NO:
alt: 'Alt'
composer:
emoji: "Emoji :)"
more_emoji: "mer..."
more_emoji: "mer"
options: "Alternativer"
whisper: "hvisker"
unlist: "skjult"
@ -984,10 +984,10 @@ nb_NO:
toggle_whisper: "Veksle hvisking"
toggle_unlisted: "Skjul eller gjør synlig"
posting_not_on_topic: "Du svarer på emnet \"{{title}}\", men for øyeblikket ser du på et annet emne."
saving_draft_tip: "lagrer..."
saving_draft_tip: "lagrer"
saved_draft_tip: "lagret"
saved_local_draft_tip: "lagret lokalt"
similar_topics: "Emnet ditt har likheter med..."
similar_topics: "Emnet ditt har likheter med"
drafts_offline: "utkast offline"
group_mentioned:
one: "Ved å nevne {{group}}, er du i ferd med å henvende deg til <a href='{{group_link}}'>{{count}} én person</a> er du sikker?"
@ -1023,7 +1023,7 @@ nb_NO:
saving: "Lagrer"
saved: "Lagret!"
saved_draft: "Innleggsutkast. Velg for å fortsette."
uploading: "Laster opp..."
uploading: "Laster opp"
show_preview: 'se forhånsvisning &raquo;'
hide_preview: '&laquo; skjul forhåndsvisning'
quote_post_title: "Siter hele innlegget"
@ -1150,7 +1150,7 @@ nb_NO:
title: "søk etter emner, innlegg, brukere eller kategorier"
no_results: "Ingen resultater funnet."
no_more_results: "Ingen flere resultater funnet."
searching: "Søker ..."
searching: "Søker"
post_format: "#{{post_number}} av {{username}}"
context:
user: "Søk i innleggene av @{{username}}"
@ -1170,7 +1170,7 @@ nb_NO:
with_tags:
label: Med stikkord
filters:
label: Returner bare emner/innlegg som...
label: Bare returner emner/innlegg som…
likes: Jeg likte
posted: jeg skrev innlegg i
watching: Jeg følger
@ -1331,7 +1331,7 @@ nb_NO:
go_bottom: "bunn"
go: "gå"
jump_bottom: "Hopp til nyeste innlegg"
jump_prompt: "hopp til..."
jump_prompt: "hopp til"
jump_prompt_of: "av %{count} innlegg"
jump_prompt_long: "Hvilken melding vil du gå til?"
jump_bottom_with_number: "hopp til innlegg %{post_number}"
@ -1385,7 +1385,7 @@ nb_NO:
delete: "Slett emne"
open: "Åpne emne"
close: "Lukk emne"
multi_select: "Velg innlegg..."
multi_select: "Velg innlegg"
auto_close: "Lukk automatisk"
pin: "Fest emnet…"
unpin: "Løsne emne…"
@ -1403,8 +1403,11 @@ nb_NO:
make_banner: "Banneremne"
remove_banner: "Fjern banneremne"
reply:
title: 'Svar'
help: 'begynn å skrive et svar til dette emnet'
post:
title: 'Svar'
topic:
title: 'Svar'
help: 'begynn å skrive et svar til dette emnet'
clear_pin:
title: "Løsne emne"
help: "Løsne feste-statusen til dette emnet slik at det ikke lenger vises på toppen av din emneliste"
@ -1444,7 +1447,7 @@ nb_NO:
banner_note: "Brukere kan fjerne banneret ved å lukke det. Kun et emne kan være banner på en og samme tid. "
no_banner_exists: "Det er ingen banneremner. "
banner_exists: "Det <strong class='badge badge-notification unread'>er</strong> for øyeblikket et banneremne. "
inviting: "Inviterer..."
inviting: "Inviterer"
automatically_add_to_groups: "Denne invitasjonen inkluderer også tilgang til disse gruppene:"
invite_private:
title: 'Invitér til samtale'
@ -1530,6 +1533,7 @@ nb_NO:
edit: "Redigerer {{link}} {{replyAvatar}} {{username}}"
edit_reason: "Begrunnelse:"
post_number: "innlegg {{number}}"
wiki_last_edited_on: "wikien sist redigert"
last_edited_on: "innlegg sist redigert"
reply_as_new_topic: "Svar med lenket emne"
continue_discussion: "Fortsetter diskusjonen fra {{postLink}}:"
@ -1703,17 +1707,18 @@ nb_NO:
hide: "Skjul versjon"
show: "Vis versjon"
revert: "Gå tilbake til denne versjonen"
edit_wiki: "Rediger wiki"
comparing_previous_to_current_out_of_total: "<strong>{{previous}}</strong> <i class='fa fa-arrows-h'></i> <strong>{{current}}</strong> / {{total}}"
displays:
inline:
title: "Vis endelig tekst med endringene der de er gjort"
button: '<i class="fa fa-square-o"></i> HTML'
button: 'HTML'
side_by_side:
title: "Vis endringer i endelig tekst side ved side"
button: '<i class="fa fa-columns"></i> HTML'
button: 'HTML'
side_by_side_markdown:
title: "Vis diff for kilderåtekst side ved side"
button: '<i class="fa fa-columns"></i> Raw'
button: ''
category:
can: 'kan&hellip;'
none: '(no category)'
@ -2160,9 +2165,9 @@ nb_NO:
custom_message_template_forum: "Hei, du burde ta del i dette forumet!"
custom_message_template_topic: "Hei, jeg tenkte du fattet interesse for dette emnet!"
safe_mode:
enabled: "Sikkert modus er påskrudd, for å gå ut av sikkert modus, lukk dette nettleservinduet"
enabled: "Sikkert modus er påskrudd, for å skru av sikkert modus, lukk dette nettleservinduet"
admin_js:
type_to_filter: "skriv for å filtrere..."
type_to_filter: "skriv for å filtrere"
admin:
title: 'Discourse Admin'
moderator: 'Moderator'
@ -2222,7 +2227,7 @@ nb_NO:
active: "Aktive"
agree: "Godta"
agree_title: "Bekreft at denne rapporteringen er gyldig og korrekt"
agree_flag_modal_title: "Godta og..."
agree_flag_modal_title: "Godta og"
agree_flag_hide_post: "Godta (skjul innlegg + send PM)"
agree_flag_hide_post_title: "Skjul dette innlegget og automatisk send brukeren en melding som oppfordrer vedkommende til å foreta endringer"
agree_flag_restore_post: "Gi medhold (gjenopprett innlegg)"
@ -2237,7 +2242,7 @@ nb_NO:
delete_post_defer_flag_title: "Slett innlegg; hvis det er første innlegg, slett emnet"
delete_post_agree_flag: "Slett innlegg og si deg enig med rapportering"
delete_post_agree_flag_title: "Slett innlegg; hvis det er første innlegg, slett emnet"
delete_flag_modal_title: "Slett og..."
delete_flag_modal_title: "Slett og"
delete_spammer: "Slett spammer"
delete_spammer_title: "Fjern denne brukeren og alle innlegg og emner av brukeren."
disagree_flag_unhide_post: "Si deg uenig med rapportering (vis innlegg)"
@ -2246,7 +2251,7 @@ nb_NO:
disagree_flag_title: "Benekt rapportering som ugyldig eller uriktig"
clear_topic_flags: "Ferdig"
clear_topic_flags_title: "Emnet har blitt undersøkt og problemer har blitt løst. Klikk Ferdig for å fjerne rapporteringene."
more: "(flere svar...)"
more: "(flere svar)"
dispositions:
agreed: "enig"
disagreed: "uenig"
@ -2426,12 +2431,12 @@ nb_NO:
upload:
label: "Last opp"
title: "Last opp en sikkerhetskopi til denne instansen"
uploading: "Laster opp..."
uploading: "Laster opp"
success: "'{{filename}}' har blitt lastet opp."
error: "Det oppsto en feil ved opplastingen av '{{filename}}': {{message}}"
operations:
is_running: "En prosess pågår..."
failed: " {{operation}} feilet. Venligst undersøk loggene."
is_running: "En prosess pågår"
failed: " {{operation}} mislyktes. Undersøk loggene."
cancel:
label: "Avbryt"
title: "Avbryt den nåværende handlingen"
@ -2458,7 +2463,7 @@ nb_NO:
confirm: "Er du sikker på at du vil gjenopprette databasen til den tidligere fungerende tilstanden?"
export_csv:
success: "Eksportering iverksatt. Du vil bli varslet med en melding når prosessen er fullført."
failed: "Eksporteringen feilet. Venligst undersøk loggene."
failed: "Eksporteringen mislyktes. Undersøk loggene."
button_text: "Eksporter"
button_title:
user: "Eksporter full medlemsliste i CSV format."
@ -2560,7 +2565,7 @@ nb_NO:
title: "E-poster"
settings: "Instillinger"
templates: "Maler"
preview_digest: "Forhåndsvis Oppsummering"
preview_digest: "Forhåndsvis oppsummering"
sending_test: "Sender e-post for testing"
error: "<b>ERROR</b> - %{server_error}"
test_error: "Det oppsto et problem ved utsendelse av e-post for testing. Sjekk e-postinnstillinger nøye, sjekk at verten ikke blokkerer e-posttilkoblinger, og prøv igjen."
@ -2586,9 +2591,9 @@ nb_NO:
format: "Format"
html: "html"
text: "tekst"
last_seen_user: "Sist Sett Bruker:"
last_seen_user: "Bruker sist sett:"
no_result: "Ingen resultater funnet for føljetong."
reply_key: "Svar ID"
reply_key: "Svar-ID"
skipped_reason: "Hopp over grunn"
incoming_emails:
from_address: "Fra"
@ -2615,8 +2620,8 @@ nb_NO:
filters:
title: "Filtrer"
user_placeholder: "brukernavn"
address_placeholder: "navn@eksempel.com"
type_placeholder: "oppsummering, registrering..."
address_placeholder: "navn@eksempel.no"
type_placeholder: "oppsummering, registrering"
reply_key_placeholder: "svarnøkkel"
skipped_reason_placeholder: "grunn"
logs:
@ -2679,12 +2684,17 @@ nb_NO:
revoke_admin: "tilbakekall admin"
grant_moderation: "innvilg moderering"
revoke_moderation: "tilbakekall moderering"
backup_operation: "sikkerhetskopier operasjon"
backup_create: "opprett sikkerhetskopi"
deleted_tag: "slettet stikkord"
renamed_tag: "stikkord med nytt navn"
revoke_email: "tilbakekall e-post"
lock_trust_level: "lås tillitsnivå"
unlock_trust_level: "lås opp tillitsnivå"
activate_user: "aktiver bruker"
deactivate_user: "deaktiver bruker"
change_readonly_mode: "endre skrivebeskyttelse"
backup_download: "last ned sikkerhetskopi"
backup_destroy: "ødelegg sikkerhetskopi"
screened_emails:
title: "Kontrollerte e-poster"
description: "Når noen forsøker å lage en ny konto, vil de følgende e-postadressene bli sjekket, og registreringen vil bli blokkert, eller en annen handling vil bli utført."
@ -2697,11 +2707,11 @@ nb_NO:
url: "URL"
domain: "Domene"
screened_ips:
title: "Kontrollerte IPs"
title: "Kontrollerte IP-er"
description: 'IP-adresser som blir fulgt. Benytt "Tillat" for å hvitliste IP-adresser.'
delete_confirm: "Er du sikker på at du vil fjerne regelen for %{ip_address}?"
roll_up_confirm: "Er du sikker på at du vil rulle opp vanligvis undersøkte IP-adresser i delnett?"
rolled_up_some_subnets: "Fullførte sammenslåingen av blokkerte IP-addresser til disse subnettene: %{subnets}."
rolled_up_some_subnets: "Fullførte sammenslåingen av blokkerte IP-adresser til disse subnettene: %{subnets}."
rolled_up_no_subnet: "Det var ingenting å slå sammen."
actions:
block: "Blokker"
@ -2727,7 +2737,7 @@ nb_NO:
create: 'Legg til Admin Bruker'
last_emailed: "Sist kontaktet"
not_found: "Beklager, det brukernavner eksisterer ikke i systemet vårt."
id_not_found: "Beklager, denne brukerID eksisterer ikke i vårt system."
id_not_found: "Denne brukerID-en eksisterer ikke i vårt system."
active: "Aktiv"
show_emails: "Vis e-poster"
nav:
@ -2759,7 +2769,7 @@ nb_NO:
moderators: 'Moderatorer'
blocked: 'Blokkerte brukere'
suspended: 'Bannlyste brukere'
suspect: 'Mistenkte Brukere'
suspect: 'Mistenkte brukere'
reject_successful:
one: "Avvist 1 bruker."
other: "Avviste %{count} brukere."
@ -2788,8 +2798,8 @@ nb_NO:
blocked: "Blokkert?"
staged: "Arrangert?"
show_admin_profile: "Admin"
edit_title: "Rediger Tittel"
save_title: "Lagre Tittel"
edit_title: "Rediger tittel"
save_title: "Lagre tittel"
refresh_browsers: "Tving nettleser refresh"
refresh_browsers_message: "Melding sendt til alle klienter!"
show_public_profile: "Vis offentlig profil"
@ -2891,8 +2901,8 @@ nb_NO:
flagged_by_users: "Brukere som rapporterte"
likes_given: "Likes tildelt"
likes_received: "Likes mottatt"
likes_received_days: "Likes Mottatt: unike dager"
likes_received_users: "Likes Mottatt: unike brukere"
likes_received_days: "Likes mottatt: Unike dager"
likes_received_users: "Likes mottatt: Unike brukere"
qualifies: "Kvalifiserer til tillitsnivå 3."
does_not_qualify: "Kvalifiserer ikke til tillitsnivå 3."
will_be_promoted: "Vil snart forfremmes."
@ -2909,7 +2919,7 @@ nb_NO:
external_avatar_url: "Profilbilde URL"
user_fields:
title: "Brukerfelter"
help: "Legg til felt som dine brukere kan fylle ut."
help: "Legg til felter som dine brukere kan fylle ut."
create: "Opprett brukerfelt"
untitled: "Uten tittel"
name: "Feltnavn"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1367,11 +1367,8 @@ pt:
make_banner: "Tópico de Faixa"
remove_banner: "Remover Tópico de Faixa"
reply:
post:
title: 'Responder'
topic:
title: 'Responder'
help: 'começa a compor uma resposta a este tópico'
title: 'Responder'
help: 'começa a compor uma resposta a este tópico'
clear_pin:
title: "Remover destaque"
help: "Remover destaque deste tópico para que o mesmo deixe de aparecer no topo da sua lista de tópicos"

View File

@ -214,7 +214,7 @@ pt_BR:
like_count: "Curtidas"
topic_count: "Tópicos"
post_count: "Mensagens"
user_count: "Novos Usuários"
user_count: "Usuários"
active_user_count: "Usuários Ativos"
contact: "Contate-nos"
contact_info: "Em caso de um evento crítico ou de urgência afetando este site, por favor contacte-nos em %{contact_info}."
@ -326,6 +326,17 @@ pt_BR:
add_user_to_group: "Adicionar usuário"
remove_user_from_group: "Remover usuário"
groups:
logs:
title: "Registros"
subject: "Assunto"
details: "Detalhes"
from: "De"
to: "Para"
edit:
title: 'Editar Grupo'
full_name: 'Nome Completo'
add_members: "Adicionar Membros"
delete_member_confirm: "Remover '%{username}' do grupo '%{group}'?"
add: "Adicionar"
selector_placeholder: "Adicionar membros"
owner: "proprietário"
@ -1144,6 +1155,7 @@ pt_BR:
new_messages_marker: "última visita"
bulk:
select_all: "Selecionar Tudo"
clear_all: "Limpar Tudo"
unlist_topics: "Tópicos Não Listados"
reset_read: "Redefinir Lido"
delete: "Apagar Tópicos"

Some files were not shown because too many files have changed in this diff Show More