Version bump
This commit is contained in:
commit
380891875e
@ -27,7 +27,7 @@ rvm:
|
||||
- 2.0.0
|
||||
- 2.1
|
||||
- 2.2
|
||||
- 2.3.0
|
||||
- 2.3.1
|
||||
|
||||
services:
|
||||
- redis-server
|
||||
|
||||
12
Gemfile.lock
12
Gemfile.lock
@ -65,7 +65,7 @@ GEM
|
||||
byebug (8.2.1)
|
||||
certified (1.0.0)
|
||||
coderay (1.1.0)
|
||||
concurrent-ruby (1.0.1)
|
||||
concurrent-ruby (1.0.2)
|
||||
connection_pool (2.2.0)
|
||||
crass (1.0.2)
|
||||
daemons (1.2.3)
|
||||
@ -92,7 +92,7 @@ GEM
|
||||
railties (>= 3.1)
|
||||
ember-source (1.12.2)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.0.8)
|
||||
eventmachine (1.2.0.1)
|
||||
excon (0.45.4)
|
||||
execjs (2.6.0)
|
||||
exifr (1.2.4)
|
||||
@ -149,7 +149,7 @@ GEM
|
||||
thor (~> 0.15)
|
||||
libv8 (3.16.14.13)
|
||||
listen (0.7.3)
|
||||
logster (1.2.2)
|
||||
logster (1.2.3)
|
||||
loofah (2.0.3)
|
||||
nokogiri (>= 1.5.9)
|
||||
lru_redux (1.1.0)
|
||||
@ -282,7 +282,7 @@ GEM
|
||||
ffi (>= 1.0.6)
|
||||
msgpack (>= 0.4.3)
|
||||
trollop (>= 1.16.2)
|
||||
redis (3.2.2)
|
||||
redis (3.3.0)
|
||||
redis-namespace (1.5.2)
|
||||
redis (~> 3.0, >= 3.0.4)
|
||||
ref (2.0.0)
|
||||
@ -344,7 +344,7 @@ GEM
|
||||
shoulda-context (1.2.1)
|
||||
shoulda-matchers (2.8.0)
|
||||
activesupport (>= 3.0.0)
|
||||
sidekiq (4.0.2)
|
||||
sidekiq (4.1.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
connection_pool (~> 2.2, >= 2.2.0)
|
||||
redis (~> 3.2, >= 3.2.1)
|
||||
@ -501,4 +501,4 @@ DEPENDENCIES
|
||||
unicorn
|
||||
|
||||
BUNDLED WITH
|
||||
1.11.2
|
||||
1.12.3
|
||||
|
||||
@ -42,7 +42,7 @@ Discourse is built for the *next* 10 years of the Internet, so our requirements
|
||||
| -------- | ------- | ----------- |
|
||||
| Safari 6.1+| iPad 2+ | iOS 7+ |
|
||||
| Google Chrome 23+ | Android 4.3+ | Android 4.3+ |
|
||||
| Internet Explorer 10+ | Windows 8 | Windows Phone 8 |
|
||||
| Internet Explorer 11+ | Windows 8 | Windows Phone 8 |
|
||||
| Firefox 16+ | |
|
||||
|
||||
## Built With
|
||||
|
||||
@ -28,7 +28,7 @@ export default Ember.Controller.extend({
|
||||
|
||||
@computed('model.type')
|
||||
showCategoryOptions(modelType) {
|
||||
return !modelType.match(/_private_messages$/);
|
||||
return !modelType.match(/_private_messages$/) && !modelType.match(/^page_view_/);
|
||||
},
|
||||
|
||||
@computed('model.type')
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
import { propertyNotEqual } from 'discourse/lib/computed';
|
||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||
import ApiKey from 'admin/models/api-key';
|
||||
@ -6,11 +7,42 @@ import TL3Requirements from 'admin/models/tl3-requirements';
|
||||
|
||||
const AdminUser = Discourse.User.extend({
|
||||
|
||||
customGroups: Em.computed.filter("groups", (g) => !g.automatic && Group.create(g)),
|
||||
automaticGroups: Em.computed.filter("groups", (g) => g.automatic && Group.create(g)),
|
||||
customGroups: Ember.computed.filter("groups", g => !g.automatic && Group.create(g)),
|
||||
automaticGroups: Ember.computed.filter("groups", g => g.automatic && Group.create(g)),
|
||||
|
||||
canViewProfile: Ember.computed.or("active", "staged"),
|
||||
|
||||
@computed("bounce_score", "reset_bounce_score_after")
|
||||
bounceScore(bounce_score, reset_bounce_score_after) {
|
||||
if (bounce_score > 0) {
|
||||
return `${bounce_score} - ${moment(reset_bounce_score_after).format('LL')}`;
|
||||
} else {
|
||||
return bounce_score;
|
||||
}
|
||||
},
|
||||
|
||||
@computed("bounce_score")
|
||||
bounceScoreExplanation(bounce_score) {
|
||||
if (bounce_score === 0) {
|
||||
return I18n.t("admin.user.bounce_score_explanation.none");
|
||||
} else if (bounce_score < Discourse.SiteSettings.bounce_score_threshold) {
|
||||
return I18n.t("admin.user.bounce_score_explanation.some");
|
||||
} else {
|
||||
return I18n.t("admin.user.bounce_score_explanation.threshold_reached");
|
||||
}
|
||||
},
|
||||
|
||||
canResetBounceScore: Ember.computed.gt("bounce_score", 0),
|
||||
|
||||
resetBounceScore() {
|
||||
return Discourse.ajax(`/admin/users/${this.get("id")}/reset_bounce_score`, {
|
||||
type: 'POST'
|
||||
}).then(() => this.setProperties({
|
||||
"bounce_score": 0,
|
||||
"reset_bounce_score_after": null
|
||||
}));
|
||||
},
|
||||
|
||||
generateApiKey() {
|
||||
const self = this;
|
||||
return Discourse.ajax("/admin/users/" + this.get('id') + "/generate_api_key", {
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<th>{{i18n 'admin.api.user'}}</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
{{#each k in model}}
|
||||
{{#each model as |k|}}
|
||||
<tr>
|
||||
<td class='key'>{{k.key}}</td>
|
||||
<td>
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
{{#each backup in model}}
|
||||
{{#each model as |backup|}}
|
||||
<tr>
|
||||
<td>{{backup.filename}}</td>
|
||||
<td>{{human-size backup.size}}</td>
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<div class='content-list span6'>
|
||||
<h3>{{i18n 'admin.badges.title'}}</h3>
|
||||
<ul>
|
||||
{{#each badge in model}}
|
||||
{{#each model as |badge|}}
|
||||
<li>
|
||||
{{#link-to 'adminBadges.show' badge.id}}
|
||||
{{badge-button badge=badge}}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<div class='content-list span6'>
|
||||
<h3>{{i18n 'admin.customize.colors.long_title'}}</h3>
|
||||
<ul>
|
||||
{{#each scheme in model}}
|
||||
{{#each model as |scheme|}}
|
||||
{{#unless scheme.is_base}}
|
||||
<li><a {{action "selectColorScheme" scheme}} {{bind-attr class="scheme.selected:active"}}>{{scheme.description}}</a></li>
|
||||
{{/unless}}
|
||||
@ -50,7 +50,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each c in colors}}
|
||||
{{#each colors as |c|}}
|
||||
<tr {{bind-attr class="c.changed c.valid:valid:invalid"}}>
|
||||
<td class="name" {{bind-attr title="c.name"}}>
|
||||
<b>{{c.translatedName}}</b>
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#unless loading}}
|
||||
{{#each r in user_reports}}
|
||||
{{#each user_reports as |r|}}
|
||||
{{admin-report-trust-level-counts report=r}}
|
||||
{{/each}}
|
||||
{{/unless}}
|
||||
@ -58,7 +58,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#unless loading}}
|
||||
{{#each r in global_reports}}
|
||||
{{#each global_reports as |r|}}
|
||||
{{admin-report-counts report=r}}
|
||||
{{/each}}
|
||||
{{/unless}}
|
||||
@ -80,7 +80,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#unless loading}}
|
||||
{{#each r in page_view_reports}}
|
||||
{{#each page_view_reports as |r|}}
|
||||
{{admin-report-counts report=r}}
|
||||
{{/each}}
|
||||
{{/unless}}
|
||||
@ -102,7 +102,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#unless loading}}
|
||||
{{#each r in private_message_reports}}
|
||||
{{#each private_message_reports as |r|}}
|
||||
{{admin-report-counts report=r}}
|
||||
{{/each}}
|
||||
{{/unless}}
|
||||
@ -124,7 +124,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#unless loading}}
|
||||
{{#each r in mobile_reports}}
|
||||
{{#each mobile_reports as |r|}}
|
||||
{{admin-report-counts report=r}}
|
||||
{{/each}}
|
||||
{{/unless}}
|
||||
@ -171,7 +171,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#unless loading}}
|
||||
{{#each r in http_reports}}
|
||||
{{#each http_reports as |r|}}
|
||||
{{admin-report-counts report=r}}
|
||||
{{/each}}
|
||||
{{/unless}}
|
||||
@ -195,7 +195,7 @@
|
||||
<p {{bind-attr class="loadingProblems:invisible"}}>
|
||||
{{i18n 'admin.dashboard.problems_found'}}
|
||||
<ul {{bind-attr class="loadingProblems:invisible"}}>
|
||||
{{#each problem in problems}}
|
||||
{{#each problems as |problem|}}
|
||||
<li>{{{problem}}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
@ -231,7 +231,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
{{#unless loading}}
|
||||
{{#each data in top_referred_topics.data}}
|
||||
{{#each top_referred_topics.data as |data|}}
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="title">
|
||||
@ -259,7 +259,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
{{#unless loading}}
|
||||
{{#each s in top_traffic_sources.data}}
|
||||
{{#each top_traffic_sources.data as |s|}}
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="title">{{s.domain}}</td>
|
||||
@ -282,7 +282,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
{{#unless loading}}
|
||||
{{#each r in top_referrers.data}}
|
||||
{{#each top_referrers.data as |r|}}
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="title">{{#link-to 'adminUser' r.user_id r.username}}{{unbound r.username}}{{/link-to}}</td>
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
<th>{{i18n 'admin.email.user'}}</th>
|
||||
<th>{{i18n 'admin.email.to_address'}}</th>
|
||||
<th>{{i18n 'admin.email.email_type'}}</th>
|
||||
<th>{{i18n 'admin.email.skipped_reason'}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@ -15,10 +14,9 @@
|
||||
<td>{{text-field value=filter.user placeholderKey="admin.email.logs.filters.user_placeholder"}}</td>
|
||||
<td>{{text-field value=filter.address placeholderKey="admin.email.logs.filters.address_placeholder"}}</td>
|
||||
<td>{{text-field value=filter.type placeholderKey="admin.email.logs.filters.type_placeholder"}}</td>
|
||||
<td>{{text-field value=filter.skipped_reason placeholderKey="admin.email.logs.filters.skipped_reason_placeholder"}}</td>
|
||||
</tr>
|
||||
|
||||
{{#each l in model}}
|
||||
{{#each model as |l|}}
|
||||
<tr>
|
||||
<td>{{format-date l.created_at}}</td>
|
||||
<td>
|
||||
@ -31,16 +29,9 @@
|
||||
</td>
|
||||
<td><a href='mailto:{{unbound l.to_address}}'>{{l.to_address}}</a></td>
|
||||
<td>{{l.email_type}}</td>
|
||||
<td>
|
||||
{{#if l.post_url}}
|
||||
<a href="{{l.post_url}}">{{l.skipped_reason}}</a>
|
||||
{{else}}
|
||||
{{l.skipped_reason}}
|
||||
{{/if}}
|
||||
</td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<tr><td colspan="5">{{i18n 'admin.email.logs.none'}}</td></tr>
|
||||
<tr><td colspan="4">{{i18n 'admin.email.logs.none'}}</td></tr>
|
||||
{{/each}}
|
||||
|
||||
</table>
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
<td>{{text-field value=filter.subject placeholderKey="admin.email.incoming_emails.filters.subject_placeholder"}}</td>
|
||||
</tr>
|
||||
|
||||
{{#each email in model}}
|
||||
{{#each model as |email|}}
|
||||
<tr>
|
||||
<td class="time">{{format-date email.created_at}}</td>
|
||||
<td class="username">
|
||||
@ -32,10 +32,10 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="addresses">
|
||||
{{#each to in email.to_addresses}}
|
||||
{{#each email.to_addresses as |to|}}
|
||||
<p><a href="mailto:{{unbound to}}" title="TO">{{unbound to}}</a></p>
|
||||
{{/each}}
|
||||
{{#each cc in email.cc_addresses}}
|
||||
{{#each email.cc_addresses as |cc|}}
|
||||
<p><a href="mailto:{{unbound cc}}" title="CC">{{unbound cc}}</a></p>
|
||||
{{/each}}
|
||||
</td>
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
<td>{{text-field value=filter.error placeholderKey="admin.email.incoming_emails.filters.error_placeholder"}}</td>
|
||||
</tr>
|
||||
|
||||
{{#each email in model}}
|
||||
{{#each model as |email|}}
|
||||
<tr>
|
||||
<td class="time">{{format-date email.created_at}}</td>
|
||||
<td class="username">
|
||||
@ -38,10 +38,10 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="addresses">
|
||||
{{#each to in email.to_addresses}}
|
||||
{{#each email.to_addresses as |to|}}
|
||||
<p><a href="mailto:{{unbound to}}" title="TO">{{unbound to}}</a></p>
|
||||
{{/each}}
|
||||
{{#each cc in email.cc_addresses}}
|
||||
{{#each email.cc_addresses as |cc|}}
|
||||
<p><a href="mailto:{{unbound cc}}" title="CC">{{unbound cc}}</a></p>
|
||||
{{/each}}
|
||||
</td>
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
<td>{{text-field value=filter.reply_key placeholderKey="admin.email.logs.filters.reply_key_placeholder"}}</td>
|
||||
</tr>
|
||||
|
||||
{{#each l in model}}
|
||||
{{#each model as |l|}}
|
||||
<tr>
|
||||
<td>{{format-date l.created_at}}</td>
|
||||
<td>
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
<td>{{text-field value=filter.skipped_reason placeholderKey="admin.email.logs.filters.skipped_reason_placeholder"}}</td>
|
||||
</tr>
|
||||
|
||||
{{#each l in model}}
|
||||
{{#each model as |l|}}
|
||||
<tr>
|
||||
<td>{{format-date l.created_at}}</td>
|
||||
<td>
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<td>{{delivery_method}}</td>
|
||||
</tr>
|
||||
|
||||
{{#each s in model.settings}}
|
||||
{{#each model.settings as |s|}}
|
||||
<tr>
|
||||
<th style='width: 25%'>{{s.name}}</th>
|
||||
<td>{{s.value}}</td>
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each e in controller}}
|
||||
{{#each controller as |e|}}
|
||||
<tr>
|
||||
<th><img class="emoji" src="{{unbound e.url}}" title="{{unbound e.name}}"></th>
|
||||
<th>:{{e.name}}:</th>
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
<td class='flaggers'>
|
||||
<table>
|
||||
<tbody>
|
||||
{{#each flagger in flaggedPost.flaggers}}
|
||||
{{#each flaggedPost.flaggers as |flagger|}}
|
||||
<tr>
|
||||
<td class='avatar'>
|
||||
{{#link-to 'adminUser' flagger.user}}
|
||||
@ -67,7 +67,7 @@
|
||||
{{#if adminOldFlagsView}}
|
||||
<table>
|
||||
<tbody>
|
||||
{{#each flagger in flaggedPost.flaggers}}
|
||||
{{#each flaggedPost.flaggers as |flagger|}}
|
||||
<tr>
|
||||
<td class='avatar'>
|
||||
{{#link-to 'adminUser' flagger.disposedBy}}
|
||||
@ -101,7 +101,7 @@
|
||||
</tr>
|
||||
{{/if}}
|
||||
|
||||
{{#each c in flaggedPost.conversations}}
|
||||
{{#each flaggedPost.conversations as |c|}}
|
||||
<tr class='message'>
|
||||
<td></td>
|
||||
<td colspan="3">
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<div class='content-list span6'>
|
||||
<h3>{{i18n 'admin.groups.edit'}}</h3>
|
||||
<ul>
|
||||
{{#each group in controller}}
|
||||
{{#each controller as |group|}}
|
||||
<li>
|
||||
{{#link-to "adminGroup" group.type group.name}}{{group.name}}
|
||||
{{#if group.userCountDisplay}}
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
{{i18n 'admin.badges.preview.sample'}}
|
||||
</p>
|
||||
<ul>
|
||||
{{#each html in processed_sample}}
|
||||
{{#each processed_sample as |html|}}
|
||||
<li>{{{html}}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<div class="modal-body">
|
||||
<div>
|
||||
<ul class='badge-groupings'>
|
||||
{{#each wc in workingCopy}}
|
||||
{{#each workingCopy as |wc|}}
|
||||
<li>
|
||||
{{#if wc.editing}}
|
||||
{{input value=wc.name}}
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each plugin in controller}}
|
||||
{{#each controller as |plugin|}}
|
||||
<tr>
|
||||
<td>
|
||||
{{#if plugin.url}}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<ul class="nav nav-stacked">
|
||||
{{nav-item route='adminPlugins.index' label="admin.plugins.title"}}
|
||||
|
||||
{{#each route in adminRoutes}}
|
||||
{{#each adminRoutes as |route|}}
|
||||
{{nav-item route=route.full_location label=route.label}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
<th>{{model.yaxis}}</th>
|
||||
</tr>
|
||||
|
||||
{{#each row in model.dataReversed}}
|
||||
{{#each model.dataReversed as |row|}}
|
||||
<tr>
|
||||
<td>{{row.x}}</td>
|
||||
<td>
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
<div class="admin-nav pull-left">
|
||||
<ul class="nav nav-stacked">
|
||||
{{#each category in controller}}
|
||||
{{#each controller as |category|}}
|
||||
{{#link-to 'adminSiteSettingsCategory' category.nameKey tagName='li' class=category.nameKey}}
|
||||
{{#link-to 'adminSiteSettingsCategory' category.nameKey class=category.nameKey}}
|
||||
{{category.name}}
|
||||
|
||||
@ -128,7 +128,7 @@
|
||||
|
||||
{{#if userFields}}
|
||||
<section class='details'>
|
||||
{{#each uf in userFields}}
|
||||
{{#each userFields as |uf|}}
|
||||
<div class='display-row'>
|
||||
<div class='field'>{{uf.name}}</div>
|
||||
<div class='value'>
|
||||
@ -350,7 +350,20 @@
|
||||
<div class="display-row">
|
||||
<div class='field'>{{i18n 'admin.user.staged'}}</div>
|
||||
<div class='value'>{{model.staged}}</div>
|
||||
<div class='controls'>{{i18n 'admin.user.stage_explanation'}}</div>
|
||||
<div class='controls'>{{i18n 'admin.user.staged_explanation'}}</div>
|
||||
</div>
|
||||
|
||||
<div class="display-row">
|
||||
<div class='field'>{{i18n 'admin.user.bounce_score'}}</div>
|
||||
<div class='value'>{{model.bounceScore}}</div>
|
||||
<div class='controls'>
|
||||
{{#if model.canResetBounceScore}}
|
||||
<button class='btn' {{action "resetBounceScore" target="content"}} title={{i18n "admin.user.reset_bounce_score.title"}}>
|
||||
{{i18n "admin.user.reset_bounce_score.label"}}
|
||||
</button>
|
||||
{{/if}}
|
||||
{{model.bounceScoreExplanation}}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
<th> </th>
|
||||
</tr>
|
||||
|
||||
{{#each user in model}}
|
||||
{{#each model as |user|}}
|
||||
<tr {{bind-attr class="user.selected user.active::not-activated"}}>
|
||||
{{#if controller.showApproval}}
|
||||
<td>
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
import { propertyEqual } from 'discourse/lib/computed';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'tr',
|
||||
classNameBindings: ['me'],
|
||||
me: propertyEqual('item.user.id', 'currentUser.id')
|
||||
});
|
||||
@ -0,0 +1,54 @@
|
||||
import { MAX_MESSAGE_LENGTH } from 'discourse/models/post-action-type';
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
|
||||
@computed('flag.name_key')
|
||||
customPlaceholder(nameKey) {
|
||||
return I18n.t("flagging.custom_placeholder_" + nameKey);
|
||||
},
|
||||
|
||||
@computed('flag.name', 'flag.name_key', 'flag.is_custom_flag', 'username')
|
||||
formattedName(name, nameKey, isCustomFlag, username) {
|
||||
if (isCustomFlag) {
|
||||
return name.replace("{{username}}", username);
|
||||
} else {
|
||||
return I18n.t("flagging.formatted_name." + nameKey);
|
||||
}
|
||||
},
|
||||
|
||||
@computed('flag', 'selectedFlag')
|
||||
selected(flag, selectedFlag) {
|
||||
return flag === selectedFlag;
|
||||
},
|
||||
|
||||
showMessageInput: Em.computed.and('flag.is_custom_flag', 'selected'),
|
||||
showDescription: Em.computed.not('showMessageInput'),
|
||||
isNotifyUser: Em.computed.equal('flag.name_key', 'notify_user'),
|
||||
|
||||
@computed('message.length')
|
||||
customMessageLengthClasses(messageLength) {
|
||||
return (messageLength < Discourse.SiteSettings.min_private_message_post_length) ? "too-short" : "ok";
|
||||
},
|
||||
|
||||
@computed('message.length')
|
||||
customMessageLength(messageLength) {
|
||||
const len = messageLength || 0;
|
||||
const minLen = Discourse.SiteSettings.min_private_message_post_length;
|
||||
if (len === 0) {
|
||||
return I18n.t("flagging.custom_message.at_least", { n: minLen });
|
||||
} else if (len < minLen) {
|
||||
return I18n.t("flagging.custom_message.more", { n: minLen - len });
|
||||
} else {
|
||||
return I18n.t("flagging.custom_message.left", {
|
||||
n: MAX_MESSAGE_LENGTH - len
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
changePostActionType(at) {
|
||||
this.sendAction('changePostActionType', at);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,5 +1,5 @@
|
||||
import { propertyEqual } from 'discourse/lib/computed';
|
||||
import BufferedContent from 'discourse/mixins/buffered-content';
|
||||
import { bufferedProperty } from 'discourse/mixins/buffered-content';
|
||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||
|
||||
function updateState(state, opts) {
|
||||
@ -12,18 +12,14 @@ function updateState(state, opts) {
|
||||
if (opts.deleteUser) { args.delete_user = true; }
|
||||
|
||||
post.update(args).then(() => {
|
||||
this.get('controllers.queued-posts.model').removeObject(post);
|
||||
this.sendAction('removePost', post);
|
||||
// this.get('controllers.queued-posts.model').removeObject(post);
|
||||
}).catch(popupAjaxError);
|
||||
};
|
||||
}
|
||||
|
||||
export default Ember.Controller.extend(BufferedContent, {
|
||||
needs: ['queued-posts'],
|
||||
post: Ember.computed.alias('model'),
|
||||
currentlyEditing: Ember.computed.alias('controllers.queued-posts.editing'),
|
||||
|
||||
editing: propertyEqual('model', 'currentlyEditing'),
|
||||
|
||||
export default Ember.Component.extend(bufferedProperty('post'), {
|
||||
editing: propertyEqual('post', 'currentlyEditing'),
|
||||
_confirmDelete: updateState('rejected', {deleteUser: true}),
|
||||
|
||||
actions: {
|
||||
@ -31,7 +27,7 @@ export default Ember.Controller.extend(BufferedContent, {
|
||||
reject: updateState('rejected'),
|
||||
|
||||
deleteUser() {
|
||||
bootbox.confirm(I18n.t('queue.delete_prompt', {username: this.get('model.user.username')}), (confirmed) => {
|
||||
bootbox.confirm(I18n.t('queue.delete_prompt', {username: this.get('post.user.username')}), (confirmed) => {
|
||||
if (confirmed) { this._confirmDelete(); }
|
||||
});
|
||||
},
|
||||
@ -39,7 +35,7 @@ export default Ember.Controller.extend(BufferedContent, {
|
||||
edit() {
|
||||
// This is stupid but pagedown cannot be on the screen twice or it will break
|
||||
this.set('currentlyEditing', null);
|
||||
Ember.run.scheduleOnce('afterRender', () => this.set('currentlyEditing', this.get('model')));
|
||||
Ember.run.scheduleOnce('afterRender', () => this.set('currentlyEditing', this.get('post')));
|
||||
},
|
||||
|
||||
confirmEdit() {
|
||||
@ -1,34 +1,19 @@
|
||||
import StringBuffer from 'discourse/mixins/string-buffer';
|
||||
|
||||
export default Ember.View.extend(StringBuffer, {
|
||||
topic: Em.computed.alias("content"),
|
||||
rerenderTriggers: ['controller.bulkSelectEnabled', 'topic.pinned'],
|
||||
export default Ember.Component.extend(StringBuffer, {
|
||||
rerenderTriggers: ['bulkSelectEnabled', 'topic.pinned'],
|
||||
tagName: 'tr',
|
||||
rawTemplate: 'list/topic-list-item.raw',
|
||||
classNameBindings: ['controller.checked',
|
||||
':topic-list-item',
|
||||
'unboundClassNames',
|
||||
'selected'],
|
||||
classNameBindings: [':topic-list-item', 'unboundClassNames'],
|
||||
attributeBindings: ['data-topic-id'],
|
||||
'data-topic-id': Em.computed.alias('topic.id'),
|
||||
|
||||
actions: {
|
||||
select() {
|
||||
this.set('controller.selectedRow', this);
|
||||
},
|
||||
|
||||
toggleBookmark() {
|
||||
const self = this;
|
||||
this.get('topic').toggleBookmark().finally(function() {
|
||||
self.rerender();
|
||||
});
|
||||
this.get('topic').toggleBookmark().finally(() => this.rerender());
|
||||
}
|
||||
},
|
||||
|
||||
selected: function() {
|
||||
return this.get('controller.selectedRow')===this;
|
||||
}.property('controller.selectedRow'),
|
||||
|
||||
unboundClassNames: function() {
|
||||
let classes = [];
|
||||
const topic = this.get('topic');
|
||||
@ -51,7 +36,7 @@ export default Ember.View.extend(StringBuffer, {
|
||||
}.property(),
|
||||
|
||||
titleColSpan: function() {
|
||||
return (!this.get('controller.hideCategory') &&
|
||||
return (!this.get('hideCategory') &&
|
||||
this.get('topic.isPinnedUncategorized') ? 2 : 1);
|
||||
}.property("topic.isPinnedUncategorized"),
|
||||
|
||||
@ -70,11 +55,11 @@ export default Ember.View.extend(StringBuffer, {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.get('controller.expandGloballyPinned') && this.get('topic.pinned_globally')) {
|
||||
if (this.get('expandGloballyPinned') && this.get('topic.pinned_globally')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.get('controller.expandAllPinned')) {
|
||||
if (this.get('expandAllPinned')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -96,7 +81,7 @@ export default Ember.View.extend(StringBuffer, {
|
||||
}
|
||||
|
||||
if (target.hasClass('bulk-select')) {
|
||||
const selected = this.get('controller.selected');
|
||||
const selected = this.get('selected');
|
||||
const topic = this.get('topic');
|
||||
|
||||
if (target.is(':checked')) {
|
||||
@ -9,7 +9,7 @@ export default MountWidget.extend({
|
||||
this.args = { notifications: this.get('notifications') };
|
||||
},
|
||||
|
||||
@observes('notifications.length')
|
||||
@observes('notifications.length', 'notifications.@each.read')
|
||||
_triggerRefresh() {
|
||||
this.queueRerender();
|
||||
}
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
import { propertyEqual } from 'discourse/lib/computed';
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
me: propertyEqual('model.user.id', 'currentUser.id')
|
||||
});
|
||||
@ -1,48 +0,0 @@
|
||||
import { MAX_MESSAGE_LENGTH } from 'discourse/models/post-action-type';
|
||||
|
||||
// Supports logic for flags in the modal
|
||||
export default Ember.Controller.extend({
|
||||
needs: ['flag'],
|
||||
|
||||
message: Em.computed.alias('controllers.flag.message'),
|
||||
isWarning: Em.computed.alias('controllers.flag.isWarning'),
|
||||
|
||||
customPlaceholder: function(){
|
||||
return I18n.t("flagging.custom_placeholder_" + this.get('model.name_key'));
|
||||
}.property('model.name_key'),
|
||||
|
||||
formattedName: function(){
|
||||
if (this.get("model.is_custom_flag")) {
|
||||
return this.get('model.name').replace("{{username}}", this.get('controllers.flag.model.username'));
|
||||
} else {
|
||||
return I18n.t("flagging.formatted_name." + this.get('model.name_key'));
|
||||
}
|
||||
}.property('model.name', 'model.name_key', 'model.is_custom_flag'),
|
||||
|
||||
selected: function() {
|
||||
return this.get('model') === this.get('controllers.flag.selected');
|
||||
}.property('controllers.flag.selected'),
|
||||
|
||||
showMessageInput: Em.computed.and('model.is_custom_flag', 'selected'),
|
||||
showDescription: Em.computed.not('showMessageInput'),
|
||||
isNotifyUser: Em.computed.equal('model.name_key', 'notify_user'),
|
||||
|
||||
customMessageLengthClasses: function() {
|
||||
return (this.get('message.length') < Discourse.SiteSettings.min_private_message_post_length) ? "too-short" : "ok";
|
||||
}.property('message.length'),
|
||||
|
||||
customMessageLength: function() {
|
||||
var len = this.get('message.length') || 0;
|
||||
var minLen = Discourse.SiteSettings.min_private_message_post_length;
|
||||
if (len === 0) {
|
||||
return I18n.t("flagging.custom_message.at_least", { n: minLen });
|
||||
} else if (len < minLen) {
|
||||
return I18n.t("flagging.custom_message.more", { n: minLen - len });
|
||||
} else {
|
||||
return I18n.t("flagging.custom_message.left", {
|
||||
n: MAX_MESSAGE_LENGTH - len
|
||||
});
|
||||
}
|
||||
}.property('message.length')
|
||||
|
||||
});
|
||||
@ -39,7 +39,6 @@ function parseName(fullName) {
|
||||
}
|
||||
|
||||
export default Ember.DefaultResolver.extend({
|
||||
|
||||
parseName: parseName,
|
||||
|
||||
normalize(fullName) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import Mobile from 'discourse/lib/mobile';
|
||||
|
||||
// Initializes the `Mobile` helper object.
|
||||
// Initializes the `Mobile` helper object.
|
||||
export default {
|
||||
name: 'mobile',
|
||||
after: 'inject-objects',
|
||||
@ -16,4 +16,3 @@ export default {
|
||||
app.registry.resolver.__resolver__.mobileView = Mobile.mobileView;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
};
|
||||
};
|
||||
|
||||
// #each .. in support
|
||||
// #each .. in support (as format is transformed to this)
|
||||
RawHandlebars.registerHelper('each', function(localName,inKeyword,contextName,options){
|
||||
var list = Em.get(this, contextName);
|
||||
var output = [];
|
||||
@ -68,6 +68,21 @@
|
||||
RawHandlebars.JavaScriptCompiler.prototype.compiler = RawHandlebars.JavaScriptCompiler;
|
||||
RawHandlebars.JavaScriptCompiler.prototype.namespace = "Discourse.EmberCompatHandlebars";
|
||||
|
||||
function buildPath(blk, args) {
|
||||
|
||||
var result = { type: "PathExpression",
|
||||
data: false,
|
||||
depth: blk.path.depth,
|
||||
loc: blk.path.loc };
|
||||
|
||||
// Server side precompile doesn't have jquery.extend
|
||||
Object.keys(args).forEach(function (a) {
|
||||
result[a] = args[a];
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function replaceGet(ast) {
|
||||
var visitor = new Handlebars.Visitor();
|
||||
visitor.mutating = true;
|
||||
@ -75,19 +90,25 @@
|
||||
visitor.MustacheStatement = function(mustache) {
|
||||
if (!(mustache.params.length || mustache.hash)) {
|
||||
mustache.params[0] = mustache.path;
|
||||
mustache.path = {
|
||||
type: "PathExpression",
|
||||
data: false,
|
||||
depth: mustache.path.depth,
|
||||
parts: ["get"],
|
||||
original: "get",
|
||||
loc: mustache.path.loc,
|
||||
strict: true,
|
||||
falsy: true
|
||||
};
|
||||
mustache.path = buildPath(mustache, { parts: ['get'], original: 'get', strict: true, falsy: true });
|
||||
}
|
||||
return Handlebars.Visitor.prototype.MustacheStatement.call(this, mustache);
|
||||
};
|
||||
|
||||
// rewrite `each x as |y|` as each y in x`
|
||||
// This allows us to use the same syntax in all templates
|
||||
visitor.BlockStatement = function(block) {
|
||||
if (block.path.original === 'each' && block.params.length === 1) {
|
||||
var paramName = block.program.blockParams[0];
|
||||
block.params = [ buildPath(block, { original: paramName }),
|
||||
{ type: "CommentStatement", value: "in" },
|
||||
block.params[0] ];
|
||||
delete block.program.blockParams;
|
||||
}
|
||||
|
||||
return Handlebars.Visitor.prototype.BlockStatement.call(this, block);
|
||||
};
|
||||
|
||||
visitor.accept(ast);
|
||||
}
|
||||
|
||||
|
||||
@ -294,10 +294,6 @@ export default {
|
||||
$articles.removeClass('selected');
|
||||
$article.addClass('selected');
|
||||
|
||||
if ($article.is('.topic-list-item')) {
|
||||
this.sendToTopicListItemView('select');
|
||||
}
|
||||
|
||||
if ($article.is('.topic-post')) {
|
||||
$('a.tabLoc', $article).focus();
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
let mobileForced = false;
|
||||
|
||||
// An object that is responsible for logic related to mobile devices.
|
||||
const Mobile = {
|
||||
isMobileDevice: false,
|
||||
@ -5,8 +7,10 @@ const Mobile = {
|
||||
|
||||
init() {
|
||||
const $html = $('html');
|
||||
this.isMobileDevice = $html.hasClass('mobile-device');
|
||||
this.mobileView = $html.hasClass('mobile-view');
|
||||
this.isMobileDevice = mobileForced || $html.hasClass('mobile-device');
|
||||
this.mobileView = mobileForced || $html.hasClass('mobile-view');
|
||||
|
||||
if (mobileForced) { return; }
|
||||
|
||||
try{
|
||||
if (window.location.search.match(/mobile_view=1/)){
|
||||
@ -27,8 +31,8 @@ const Mobile = {
|
||||
}
|
||||
},
|
||||
|
||||
toggleMobileView: function() {
|
||||
try{
|
||||
toggleMobileView() {
|
||||
try {
|
||||
if (localStorage) {
|
||||
localStorage.mobileView = !this.mobileView;
|
||||
}
|
||||
@ -38,11 +42,19 @@ const Mobile = {
|
||||
this.reloadPage(!this.mobileView);
|
||||
},
|
||||
|
||||
reloadPage: function(mobile) {
|
||||
reloadPage(mobile) {
|
||||
window.location.assign(window.location.pathname + '?mobile_view=' + (mobile ? '1' : '0'));
|
||||
}
|
||||
};
|
||||
|
||||
export function forceMobile() {
|
||||
mobileForced = true;
|
||||
}
|
||||
|
||||
export function resetMobile() {
|
||||
mobileForced = false;
|
||||
}
|
||||
|
||||
// Backwards compatibiltity, deprecated
|
||||
Object.defineProperty(Discourse, 'Mobile', {
|
||||
get: function() {
|
||||
|
||||
@ -139,9 +139,7 @@ const DiscourseURL = Ember.Object.extend({
|
||||
}
|
||||
}
|
||||
|
||||
rewrites.forEach(function(rw) {
|
||||
path = path.replace(rw.regexp, rw.replacement);
|
||||
});
|
||||
rewrites.forEach(rw => path = path.replace(rw.regexp, rw.replacement));
|
||||
|
||||
if (this.navigatedToPost(oldPath, path)) { return; }
|
||||
// Schedule a DOM cleanup event
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import buildCategoryRoute from 'discourse/routes/build-category-route';
|
||||
import buildTopicRoute from 'discourse/routes/build-topic-route';
|
||||
import DiscoverySortableController from 'discourse/controllers/discovery-sortable';
|
||||
import TagsShowRoute from 'discourse/routes/tags-show';
|
||||
|
||||
export default {
|
||||
after: 'inject-discourse-objects',
|
||||
name: 'dynamic-route-builders',
|
||||
|
||||
initialize(container, app) {
|
||||
initialize(registry, app) {
|
||||
app.DiscoveryCategoryController = DiscoverySortableController.extend();
|
||||
app.DiscoveryParentCategoryController = DiscoverySortableController.extend();
|
||||
app.DiscoveryCategoryNoneController = DiscoverySortableController.extend();
|
||||
@ -58,5 +59,14 @@ export default {
|
||||
app[`DiscoveryTop${periodCapitalized}ParentCategoryRoute`] = buildCategoryRoute('top/' + period);
|
||||
app[`DiscoveryTop${periodCapitalized}CategoryNoneRoute`] = buildCategoryRoute('top/' + period, {no_subcategories: true});
|
||||
});
|
||||
|
||||
app["TagsShowCategoryRoute"] = TagsShowRoute.extend();
|
||||
app["TagsShowParentCategoryRoute"] = TagsShowRoute.extend();
|
||||
|
||||
site.get('filters').forEach(function(filter) {
|
||||
app["TagsShow" + filter.capitalize() + "Route"] = TagsShowRoute.extend({ filterMode: filter });
|
||||
app["TagsShowCategory" + filter.capitalize() + "Route"] = TagsShowRoute.extend({ filterMode: filter });
|
||||
app["TagsShowParentCategory" + filter.capitalize() + "Route"] = TagsShowRoute.extend({ filterMode: filter });
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -13,6 +13,10 @@ export default DiscourseRoute.extend({
|
||||
},
|
||||
|
||||
actions: {
|
||||
removePost(post) {
|
||||
this.modelFor('queued-posts').removeObject(post);
|
||||
},
|
||||
|
||||
refresh() {
|
||||
this.modelFor('queued-posts').refresh();
|
||||
}
|
||||
|
||||
@ -7,6 +7,13 @@ export default Discourse.Route.extend({
|
||||
return I18n.t("tagging.tags");
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
this.controllerFor('tags.index').setProperties({
|
||||
model,
|
||||
sortProperties: this.siteSettings.tags_sort_alphabetically ? ['id'] : ['count:desc', 'id']
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
didTransition() {
|
||||
this.controllerFor("application").set("showFooter", true);
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<h1>{{i18n 'badges.title'}}</h1>
|
||||
|
||||
<div class='badge-groups'>
|
||||
{{#each bg in badgeGroups}}
|
||||
{{#each badgeGroups as |bg|}}
|
||||
<div class='badge-grouping'>
|
||||
<div class='title'>
|
||||
<h3>{{bg.badgeGrouping.displayName}}</h3>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<div class='autocomplete'>
|
||||
<ul>
|
||||
{{#each option in options}}
|
||||
{{#each options as |option|}}
|
||||
<li><a href>{{category-link option allowUncategorized="true" link="false"}}</a></li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<div class='autocomplete'>
|
||||
<ul>
|
||||
{{#each option in options}}
|
||||
{{#each options as |option|}}
|
||||
<li>
|
||||
{{#if option.model}}
|
||||
<a href>{{category-link option.model allowUncategorized="true" link="false"}}</a>
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
{{#if view.noResults}}
|
||||
<p>{{i18n 'choose_topic.none_found'}}</p>
|
||||
{{else}}
|
||||
{{#each t in view.topics}}
|
||||
{{#each view.topics as |t|}}
|
||||
<div class='controls'>
|
||||
<label class='radio'>
|
||||
<input type='radio' id="choose-topic-{{unbound t.id}}" name='choose_topic_id' {{action "chooseTopic" t target="view"}}>{{t.title}}
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
<div class='cat'><a {{bind-attr href=noCategoriesUrl}} data-drop-close="true" class='badge-category home'>{{i18n 'categories.no_subcategory'}}</a></div>
|
||||
{{/if}}
|
||||
{{#if renderCategories}}
|
||||
{{#each c in categories}}<div class='cat'>{{category-link c allowUncategorized=true hideParent=subCategory}}</div>{{/each}}
|
||||
{{#each categories as |c|}}<div class='cat'>{{category-link c allowUncategorized=true hideParent=subCategory}}</div>{{/each}}
|
||||
{{/if}}
|
||||
</section>
|
||||
{{/if}}
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
<td>{{user-info user=item.user}}</td>
|
||||
<td>{{number item.likes_received}}</td>
|
||||
<td>{{number item.likes_given}}</td>
|
||||
<td>{{number item.topic_count}}</td>
|
||||
<td>{{number item.post_count}}</td>
|
||||
<td>{{number item.topics_entered}}</td>
|
||||
<td>{{number item.posts_read}}</td>
|
||||
<td>{{number item.days_visited}}</td>
|
||||
{{#if showTimeRead}}
|
||||
<td><span class='time-read'>{{unbound item.time_read}}</span></td>
|
||||
{{/if}}
|
||||
@ -0,0 +1,27 @@
|
||||
{{#if isNotifyUser}}
|
||||
<h3>{{formattedName}}</h3>
|
||||
<div class='controls'>
|
||||
<label class='radio'><input type='radio' id="radio_{{unbound flag.name_key}}" {{action "changePostActionType" flag}} name='post_action_type_index'> <span class='description'>{{{flag.description}}}</span></label>
|
||||
{{#if showMessageInput}}
|
||||
{{textarea name="message" class="flag-message" placeholder=customPlaceholder value=message}}
|
||||
<div {{bind-attr class=":custom-message-length customMessageLengthClasses"}}>{{customMessageLength}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if staffFlagsAvailable}}
|
||||
<hr>
|
||||
<h3>{{i18n 'flagging.notify_staff'}}</h3>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<div class='controls'>
|
||||
<label class='radio'>
|
||||
<input type='radio' id="radio_{{unbound flag.name_key}}" {{action "changePostActionType" flag}} name='post_action_type_index'> <strong>{{formattedName}}</strong>
|
||||
{{#if showDescription}}
|
||||
<div class='description'>{{{flag.description}}}</div>
|
||||
{{/if}}
|
||||
</label>
|
||||
{{#if showMessageInput}}
|
||||
{{textarea name="message" class="flag-message" placeholder=customPlaceholder value=message}}
|
||||
<div {{bind-attr class=":custom-message-length customMessageLengthClasses"}}>{{customMessageLength}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
@ -60,7 +60,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each a in other_accounts}}
|
||||
{{#each other_accounts as |a|}}
|
||||
<tr>
|
||||
<td>{{#link-to "adminUser" a}}{{avatar a usernamePath="user.username" imageSize="small"}} {{a.username}}{{/link-to}}</td>
|
||||
<td>{{a.trustLevel.id}}</td>
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
{{#each b in buttons}}
|
||||
{{#each buttons as |b|}}
|
||||
<button {{bind-attr class=":btn :btn-social b.name"}} {{action "externalLogin" b}}>{{b.title}}</button>
|
||||
{{/each}}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
<div id='period-popup' {{bind-attr class="showPeriods::hidden :period-popup"}}>
|
||||
<ul>
|
||||
{{#each p in site.periods}}
|
||||
{{#each site.periods as |p|}}
|
||||
<li><a href {{action "changePeriod" p}}>{{period-title p showDateRange=true}}</a></li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
@ -0,0 +1,79 @@
|
||||
<div class='queued-post'>
|
||||
<div class='poster'>
|
||||
{{#user-link user=post.user}}
|
||||
{{avatar post.user imageSize="large"}}
|
||||
{{/user-link}}
|
||||
</div>
|
||||
<div class='cooked'>
|
||||
<div class='names'>
|
||||
<span class="username">
|
||||
{{#user-link user=post.user}}
|
||||
{{post.user.username}}
|
||||
{{/user-link}}
|
||||
{{#if post.user.blocked}}
|
||||
<i class='fa fa-ban' title='{{i18n "user.blocked_tooltip"}}'></i>
|
||||
{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
<div class='post-info'>
|
||||
<span class='post-date'>{{age-with-tooltip post.created_at}}</span>
|
||||
</div>
|
||||
<div class='clearfix'></div>
|
||||
|
||||
<span class='post-title'>
|
||||
{{i18n "queue.topic"}}
|
||||
{{#if post.topic}}
|
||||
{{topic-link post.topic}}
|
||||
{{else}}
|
||||
{{post.post_options.title}}
|
||||
{{/if}}
|
||||
{{category-badge post.category}}
|
||||
</span>
|
||||
|
||||
<div class='body'>
|
||||
{{#if editing}}
|
||||
{{d-editor value=buffered.raw}}
|
||||
{{else}}
|
||||
{{{cook-text post.raw}}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class='queue-controls'>
|
||||
{{#if editing}}
|
||||
{{d-button action="confirmEdit"
|
||||
label="queue.confirm"
|
||||
disabled=post.isSaving
|
||||
class="btn-primary confirm"}}
|
||||
{{d-button action="cancelEdit"
|
||||
label="queue.cancel"
|
||||
icon="times"
|
||||
disabled=post.isSaving
|
||||
class="btn-danger cancel"}}
|
||||
{{else}}
|
||||
{{d-button action="approve"
|
||||
disabled=post.isSaving
|
||||
label="queue.approve"
|
||||
icon="check"
|
||||
class="btn-primary approve"}}
|
||||
{{d-button action="reject"
|
||||
disabled=post.isSaving
|
||||
label="queue.reject"
|
||||
icon="times"
|
||||
class="btn-danger reject"}}
|
||||
{{#if post.can_delete_user}}
|
||||
{{d-button action="deleteUser"
|
||||
disabled=post.isSaving
|
||||
label="queue.delete_user"
|
||||
icon="trash"
|
||||
class="btn-danger delete-user"}}
|
||||
{{/if}}
|
||||
{{d-button action="edit"
|
||||
disabled=post.isSaving
|
||||
label="queue.edit"
|
||||
icon="pencil"
|
||||
class="edit"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class='clearfix'></div>
|
||||
</div>
|
||||
@ -10,7 +10,7 @@
|
||||
<section {{bind-attr class="expanded::hidden :category-dropdown-menu :chooser"}}>
|
||||
<div class='cat'><a {{bind-attr href=allTagsUrl}} data-drop-close="true" class='badge-category home'>{{allTagsLabel}}</a></div>
|
||||
{{#if renderTags}}
|
||||
{{#each t in tags}}
|
||||
{{#each tags as |t|}}
|
||||
<div class='cat'>
|
||||
{{tag-drop-link tagId=t category=currentCategory}}
|
||||
</div>
|
||||
@ -18,4 +18,4 @@
|
||||
{{/if}}
|
||||
</section>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
{{#each p in periods}}
|
||||
{{#each periods as |p|}}
|
||||
{{#d-button action="changePeriod" actionParam=p}}
|
||||
{{period-title p}}
|
||||
{{/d-button}}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
{{bound-category-link topic.category hideParent=true}}
|
||||
{{#if siteSettings.tagging_enabled}}
|
||||
<div class="list-tags">
|
||||
{{#each t in topic.tags}}
|
||||
{{#each topic.tags as |t|}}
|
||||
{{discourse-tag t}}
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
@ -15,5 +15,17 @@
|
||||
</thead>
|
||||
{{/unless}}
|
||||
<tbody>
|
||||
{{each topic in topics itemView="topic-list-item"}}
|
||||
{{#each topics as |topic|}}
|
||||
{{topic-list-item topic=topic
|
||||
bulkSelectEnabled=bulkSelectEnabled
|
||||
showTopicPostBadges=showTopicPostBadges
|
||||
hideCategory=hideCategory
|
||||
showPosters=showPosters
|
||||
showParticipants=showParticipants
|
||||
showLikes=showLikes
|
||||
showOpLikes=showOpLikes
|
||||
expandGloballyPinned=expandGloballyPinned
|
||||
expandAllPinned=expandAllPinned
|
||||
selected=selected}}
|
||||
{{/each}}
|
||||
</tbody>
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each c in model.categories}}
|
||||
{{#each model.categories as |c|}}
|
||||
<tr data-category_id='{{unbound c.id}}' {{bind-attr class="c.description_excerpt:has-description:no-description c.logo_url:has-logo:no-logo"}}>
|
||||
<td class='category' style={{border-color c.color}}>
|
||||
<div>
|
||||
@ -41,7 +41,7 @@
|
||||
<td class='stats' {{bind-attr title="c.topicStatsTitle"}}>
|
||||
<table class="categoryStats">
|
||||
<tbody>
|
||||
{{#each s in c.topicCountStats}}
|
||||
{{#each c.topicCountStats as |s|}}
|
||||
<tr>
|
||||
<td class="value">{{s.value}}</td>
|
||||
<td class="unit"> / {{s.unit}}</td>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<div class='autocomplete'>
|
||||
<ul>
|
||||
{{#each option in options}}
|
||||
{{#each options as |option|}}
|
||||
<li>
|
||||
<a href>
|
||||
{{#if option.src}}
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
<div class='emoji-modal'>
|
||||
<ul class='toolbar'>
|
||||
{{#each item in toolbarItems}}<li><a title='{{item.title}}' {{#if item.selected}}class='selected'{{/if}} data-group-id='{{item.groupId}}'><img src='{{item.src}}' class='emoji'></a></li>{{/each}}
|
||||
{{#each toolbarItems as |item|}}<li><a title='{{item.title}}' {{#if item.selected}}class='selected'{{/if}} data-group-id='{{item.groupId}}'><img src='{{item.src}}' class='emoji'></a></li>{{/each}}
|
||||
</ul>
|
||||
<div class='emoji-table-wrapper'>
|
||||
<table class='emoji-page'>
|
||||
{{#each row in rows}}
|
||||
{{#each rows as |row|}}
|
||||
<tr>
|
||||
{{#each item in row}}
|
||||
{{#each row as |item|}}
|
||||
<td><a title='{{item.title}}'><img src='{{item.src}}' class='emoji'></a></td>
|
||||
{{/each}}
|
||||
</tr>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<div class='autocomplete'>
|
||||
<ul>
|
||||
{{#each option in options}}
|
||||
{{#each options as |option|}}
|
||||
<li><a href>{{option.name}}</a></li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<td class='posters'>
|
||||
{{#each poster in posters}}
|
||||
{{#each posters as |poster|}}
|
||||
<a href="{{poster.user.path}}" data-user-card="{{poster.user.username}}" class="{{poster.extras}}">{{avatar poster avatarTemplatePath="user.avatar_template" usernamePath="user.username" imageSize="small"}}</a>
|
||||
{{/each}}
|
||||
</td>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
{{#if controller.bulkSelectEnabled}}
|
||||
{{#if bulkSelectEnabled}}
|
||||
<td class='star'>
|
||||
<input type="checkbox" class="bulk-select">
|
||||
</td>
|
||||
@ -8,12 +8,12 @@
|
||||
{{raw "topic-status" topic=topic}}
|
||||
{{topic-link topic}}
|
||||
{{plugin-outlet "topic-list-after-title"}}
|
||||
{{#if controller.showTopicPostBadges}}
|
||||
{{#if showTopicPostBadges}}
|
||||
{{raw "topic-post-badges" unread=topic.unread newPosts=topic.displayNewPosts unseen=topic.unseen url=topic.lastUnreadUrl}}
|
||||
{{/if}}
|
||||
{{#if topic.tags}}
|
||||
<div class='discourse-tags'>
|
||||
{{#each tag in topic.visibleListTags}}
|
||||
{{#each topic.visibleListTags as |tag|}}
|
||||
{{discourse-tag tag}}
|
||||
{{/each}}
|
||||
</div>
|
||||
@ -25,23 +25,23 @@
|
||||
{{raw "list/action-list" topic=topic postNumbers=topic.liked_post_numbers className="likes" icon="heart"}}
|
||||
</td>
|
||||
|
||||
{{#unless controller.hideCategory}}
|
||||
{{#unless hideCategory}}
|
||||
{{#unless topic.isPinnedUncategorized}}
|
||||
{{raw "list/category-column" category=topic.category}}
|
||||
{{/unless}}
|
||||
{{/unless}}
|
||||
|
||||
{{#if controller.showPosters}}
|
||||
{{#if showPosters}}
|
||||
{{raw "list/posters-column" posters=topic.posters}}
|
||||
{{/if}}
|
||||
|
||||
{{raw "list/posts-count-column" topic=topic}}
|
||||
|
||||
{{#if controller.showParticipants}}
|
||||
{{#if showParticipants}}
|
||||
{{raw "list/posters-column" posters=topic.participants}}
|
||||
{{/if}}
|
||||
|
||||
{{#if controller.showLikes}}
|
||||
{{#if showLikes}}
|
||||
<td class="num likes">
|
||||
{{#if hasLikes}}
|
||||
<a href='{{topic.summaryUrl}}'>
|
||||
@ -50,7 +50,7 @@
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if controller.showOpLikes}}
|
||||
{{#if showOpLikes}}
|
||||
<td class="num likes">
|
||||
{{#if hasOpLikes}}
|
||||
<a href='{{topic.summaryUrl}}'>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
{{#if topics}}
|
||||
<table class="topic-list">
|
||||
<tbody>
|
||||
{{#each t in topics}}
|
||||
{{#each topics as |t|}}
|
||||
<tr {{bind-attr class="t.archived"}} data-topic-id={{t.id}}>
|
||||
<td>
|
||||
<div class='main-link'>
|
||||
@ -39,7 +39,7 @@
|
||||
{{/unless}}
|
||||
{{#if controller.showParticipants}}
|
||||
<div class='participants'>
|
||||
{{#each p in participants}}
|
||||
{{#each participants as |p|}}
|
||||
<a href="{{unbound p.user.path}}" class="{{unbound p.extras}}">{{avatar p usernamePath="user.username" imageSize="small"}}</a>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
{{user-info user=item.user}}
|
||||
{{user-stat value=item.likes_received label="directory.likes_received" icon="heart"}}
|
||||
{{user-stat value=item.likes_given label="directory.likes_given" icon="heart"}}
|
||||
{{user-stat value=item.topic_count label="directory.topic_count"}}
|
||||
{{user-stat value=item.post_count label="directory.post_count"}}
|
||||
{{user-stat value=item.topics_entered label="directory.topics_entered"}}
|
||||
{{user-stat value=item.posts_read label="directory.posts_read"}}
|
||||
{{user-stat value=item.days_visited label="directory.days_visited"}}
|
||||
{{#if showTimeRead}}
|
||||
<div class='time-read'>{{unbound item.time_read}}</div>
|
||||
{{/if}}
|
||||
@ -15,7 +15,7 @@
|
||||
</tr>
|
||||
{{/if}}
|
||||
|
||||
{{#each t in c.topics}}
|
||||
{{#each c.topics as |t|}}
|
||||
<tr {{bind-attr class="t.archived :category-topic-link"}}>
|
||||
<td class='main-link'>
|
||||
<div class='topic-inset'>
|
||||
@ -46,7 +46,7 @@
|
||||
<tr class="subcategories-list">
|
||||
<td>
|
||||
<div class='subcategories'>
|
||||
{{#each subcategory in c.subcategories}}
|
||||
{{#each c.subcategories as |subcategory|}}
|
||||
{{category-link subcategory}}
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
@ -1,35 +1,35 @@
|
||||
<td>
|
||||
{{~#unless content.hasExcerpt}}
|
||||
{{~#unless topic.hasExcerpt}}
|
||||
<div class='pull-left'>
|
||||
<a href="{{content.lastPostUrl}}">{{avatar content.lastPoster imageSize="large"}}</a>
|
||||
<a href="{{topic.lastPostUrl}}">{{avatar topic.lastPoster imageSize="large"}}</a>
|
||||
</div>
|
||||
<div class='right'>
|
||||
{{else}}
|
||||
<div>
|
||||
{{/unless~}}
|
||||
<div class='main-link'>
|
||||
{{raw "topic-status" topic=content}}
|
||||
{{topic-link content}}
|
||||
{{#if content.unseen}}
|
||||
{{raw "topic-status" topic=topic}}
|
||||
{{topic-link topic}}
|
||||
{{#if topic.unseen}}
|
||||
<span class="badge-notification new-topic"></span>
|
||||
{{/if}}
|
||||
{{raw "list/topic-excerpt" topic=content}}
|
||||
{{raw "list/topic-excerpt" topic=topic}}
|
||||
</div>
|
||||
|
||||
<div class='pull-right'>
|
||||
{{raw "list/post-count-or-badges" topic=content postBadgesEnabled=controller.showTopicPostBadges}}
|
||||
{{raw "list/post-count-or-badges" topic=topic postBadgesEnabled=controller.showTopicPostBadges}}
|
||||
</div>
|
||||
|
||||
<div class="topic-item-stats clearfix">
|
||||
{{#unless controller.hideCategory}}
|
||||
<div class='category'>
|
||||
{{category-link content.category}}
|
||||
{{category-link topic.category}}
|
||||
</div>
|
||||
{{/unless}}
|
||||
|
||||
{{#if context.topic.tags}}
|
||||
<div class='discourse-tags'>
|
||||
{{#each tag in context.topic.visibleListTags}}
|
||||
{{#each context.topic.visibleListTags as |tag|}}
|
||||
{{discourse-tag tag}}
|
||||
{{/each}}
|
||||
</div>
|
||||
@ -39,7 +39,7 @@
|
||||
|
||||
<div class="pull-right">
|
||||
<div class='num activity last'>
|
||||
<span class="age activity" title="{{content.bumpedAtTitle}}"><a href="{{content.lastPostUrl}}">{{format-date content.bumpedAt format="tiny" noTitle="true"}}</a></span>
|
||||
<span class="age activity" title="{{topic.bumpedAtTitle}}"><a href="{{topic.lastPostUrl}}">{{format-date topic.bumpedAt format="tiny" noTitle="true"}}</a></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -9,24 +9,9 @@
|
||||
{{#conditional-loading-spinner condition=model.loading}}
|
||||
{{#if model.length}}
|
||||
<div class='total-rows'>{{i18n "directory.total_rows" count=model.totalRows}}</div>
|
||||
|
||||
{{#each ic in model itemController="directory-item"}}
|
||||
<div class="user {{if ic.me 'me'}}">
|
||||
{{#with ic.model as |it|}}
|
||||
{{user-info user=it.user}}
|
||||
{{user-stat value=it.likes_received label="directory.likes_received" icon="heart"}}
|
||||
{{user-stat value=it.likes_given label="directory.likes_given" icon="heart"}}
|
||||
{{user-stat value=it.topic_count label="directory.topic_count"}}
|
||||
{{user-stat value=it.post_count label="directory.post_count"}}
|
||||
{{user-stat value=it.topics_entered label="directory.topics_entered"}}
|
||||
{{user-stat value=it.posts_read label="directory.posts_read"}}
|
||||
{{user-stat value=it.days_visited label="directory.days_visited"}}
|
||||
{{#if showTimeRead}}
|
||||
<div class='time-read'>{{unbound it.time_read}}</div>
|
||||
{{/if}}
|
||||
{{/with}}
|
||||
</div>
|
||||
{{/each}}
|
||||
{{#each model as |item|}}
|
||||
{{directory-item tagName="div" class="user" item=item showTimeRead=showTimeRead}}
|
||||
{{/each}}
|
||||
|
||||
{{conditional-loading-spinner condition=model.loadingMore}}
|
||||
{{else}}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
{{#each level in notificationLevels}}
|
||||
{{#each notificationLevels as |level|}}
|
||||
<div class='controls'>
|
||||
<label class='radio'>
|
||||
{{radio-button value=level.id name="notification_level" selection=controller.notificationLevelId}} <strong>{{unbound level.name}}</strong>
|
||||
|
||||
@ -81,7 +81,7 @@
|
||||
|
||||
{{#if userFields}}
|
||||
<div class='user-fields'>
|
||||
{{#each f in userFields}}
|
||||
{{#each userFields as |f|}}
|
||||
{{user-field field=f.field value=f.value}}
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
@ -1,34 +1,13 @@
|
||||
<div class="modal-body flag-modal">
|
||||
|
||||
<form>
|
||||
{{#each f in flagsAvailable itemController="flag-action-type"}}
|
||||
{{#if f.isNotifyUser}}
|
||||
<h3>{{f.formattedName}}</h3>
|
||||
<div class='controls'>
|
||||
<label class='radio'><input type='radio' id="radio_{{unbound f.model.name_key}}" {{action "changePostActionType" f}} name='post_action_type_index'> <span class='description'>{{{f.model.description}}}</span></label>
|
||||
{{#if f.showMessageInput}}
|
||||
{{textarea name="message" class="flag-message" placeholder=f.customPlaceholder value=f.message}}
|
||||
<div {{bind-attr class=":custom-message-length f.customMessageLengthClasses"}}>{{f.customMessageLength}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if staffFlagsAvailable}}
|
||||
<hr>
|
||||
<h3>{{i18n 'flagging.notify_staff'}}</h3>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<div class='controls'>
|
||||
<label class='radio'>
|
||||
<input type='radio' id="radio_{{unbound f.model.name_key}}" {{action "changePostActionType" f}} name='post_action_type_index'> <strong>{{f.formattedName}}</strong>
|
||||
{{#if f.showDescription}}
|
||||
<div class='description'>{{{f.model.description}}}</div>
|
||||
{{/if}}
|
||||
</label>
|
||||
{{#if f.showMessageInput}}
|
||||
{{textarea name="message" class="flag-message" placeholder=f.customPlaceholder value=f.message}}
|
||||
<div {{bind-attr class=":custom-message-length f.customMessageLengthClasses"}}>{{f.customMessageLength}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#each flagsAvailable as |f|}}
|
||||
{{flag-action-type flag=f
|
||||
message=message
|
||||
isWarning=isWarning
|
||||
selectedFlag=selected
|
||||
username=model.username
|
||||
changePostActionType="changePostActionType"}}
|
||||
{{else}}
|
||||
{{i18n 'flagging.cant'}}
|
||||
{{/each}}
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
</div>
|
||||
<div id='modal-alert'></div>
|
||||
{{outlet "modalBody"}}
|
||||
{{#each error in errors}}
|
||||
{{#each errors as |error|}}
|
||||
<div class="alert alert-error">
|
||||
<button class="close" data-dismiss="alert">×</button>
|
||||
{{error}}
|
||||
|
||||
@ -1,85 +1,7 @@
|
||||
<div class='container'>
|
||||
<div class='queued-posts'>
|
||||
{{#each ctrl in model itemController='queued-post'}}
|
||||
<div class='queued-post'>
|
||||
<div class='poster'>
|
||||
{{#user-link user=ctrl.post.user}}
|
||||
{{avatar ctrl.post.user imageSize="large"}}
|
||||
{{/user-link}}
|
||||
</div>
|
||||
<div class='cooked'>
|
||||
<div class='names'>
|
||||
<span class="username">
|
||||
{{#user-link user=ctrl.post.user}}
|
||||
{{ctrl.post.user.username}}
|
||||
{{/user-link}}
|
||||
{{#if ctrl.post.user.blocked}}
|
||||
<i class='fa fa-ban' title='{{i18n "user.blocked_tooltip"}}'></i>
|
||||
{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
<div class='post-info'>
|
||||
<span class='post-date'>{{age-with-tooltip ctrl.post.created_at}}</span>
|
||||
</div>
|
||||
<div class='clearfix'></div>
|
||||
|
||||
<span class='post-title'>
|
||||
{{i18n "queue.topic"}}
|
||||
{{#if ctrl.post.topic}}
|
||||
{{topic-link ctrl.post.topic}}
|
||||
{{else}}
|
||||
{{ctrl.post.post_options.title}}
|
||||
{{/if}}
|
||||
{{category-badge ctrl.post.category}}
|
||||
</span>
|
||||
|
||||
<div class='body'>
|
||||
{{#if ctrl.editing}}
|
||||
{{d-editor value=ctrl.buffered.raw}}
|
||||
{{else}}
|
||||
{{{cook-text ctrl.post.raw}}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class='queue-controls'>
|
||||
{{#if ctrl.editing}}
|
||||
{{d-button action="confirmEdit"
|
||||
label="queue.confirm"
|
||||
disabled=ctrl.post.isSaving
|
||||
class="btn-primary confirm"}}
|
||||
{{d-button action="cancelEdit"
|
||||
label="queue.cancel"
|
||||
icon="times"
|
||||
disabled=ctrl.post.isSaving
|
||||
class="btn-danger cancel"}}
|
||||
{{else}}
|
||||
{{d-button action="approve"
|
||||
disabled=ctrl.post.isSaving
|
||||
label="queue.approve"
|
||||
icon="check"
|
||||
class="btn-primary approve"}}
|
||||
{{d-button action="reject"
|
||||
disabled=ctrl.post.isSaving
|
||||
label="queue.reject"
|
||||
icon="times"
|
||||
class="btn-danger reject"}}
|
||||
{{#if ctrl.post.can_delete_user}}
|
||||
{{d-button action="deleteUser"
|
||||
disabled=ctrl.post.isSaving
|
||||
label="queue.delete_user"
|
||||
icon="trash"
|
||||
class="btn-danger delete-user"}}
|
||||
{{/if}}
|
||||
{{d-button action="edit"
|
||||
disabled=ctrl.post.isSaving
|
||||
label="queue.edit"
|
||||
icon="pencil"
|
||||
class="edit"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class='clearfix'></div>
|
||||
</div>
|
||||
{{#each model as |post|}}
|
||||
{{queued-post post=post currentlyEditing=editing removePost="removePost"}}
|
||||
{{else}}
|
||||
<p>{{i18n "queue.none"}}</p>
|
||||
{{/each}}
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<div class="share-for-touch"><div class="overflow-ellipsis"><a></a></div></div>
|
||||
</div>
|
||||
|
||||
{{#each s in sources}}
|
||||
{{#each sources as |s|}}
|
||||
{{share-source source=s title=view.title action="share"}}
|
||||
{{/each}}
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
</div>
|
||||
|
||||
<div class='tag-list'>
|
||||
{{#each tag in sortedTags}}
|
||||
{{#each sortedTags as |tag|}}
|
||||
<div class='tag-box'>
|
||||
{{discourse-tag tag.id}} <span class='tag-count'>x {{tag.count}}</span>
|
||||
</div>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{{~#if view.renderDiv ~}}
|
||||
<div class='topic-statuses'>
|
||||
{{/if ~}}
|
||||
{{~#each status in view.statuses ~}}
|
||||
{{~#each view.statuses as |status|~}}
|
||||
{{~#if status.href ~}}
|
||||
<a href='{{status.href}}' title='{{status.title}}' class='topic-status {{status.extraClasses}}'><i class='fa fa-{{status.icon}}'></i></a>
|
||||
{{~else ~}}
|
||||
|
||||
@ -86,7 +86,7 @@
|
||||
|
||||
{{#if publicUserFields}}
|
||||
<div class="public-user-fields">
|
||||
{{#each uf in publicUserFields}}
|
||||
{{#each publicUserFields as |uf|}}
|
||||
{{#if uf.value}}
|
||||
<div class="public-user-field {{uf.field.dasherized_name}}">
|
||||
<span class="user-field-name">{{uf.field.name}}:</span>
|
||||
@ -99,7 +99,7 @@
|
||||
|
||||
{{#if showBadges}}
|
||||
<div class="badge-section">
|
||||
{{#each ub in user.featured_user_badges}}
|
||||
{{#each user.featured_user_badges as |ub|}}
|
||||
{{user-badge badge=ub.badge user=user}}
|
||||
{{/each}}
|
||||
{{#if showMoreBadges}}
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
<th colspan="6">{{i18n 'user.invited.sent'}}</th>
|
||||
{{/if}}
|
||||
</tr>
|
||||
{{#each invite in model.invites}}
|
||||
{{#each model.invites as |invite|}}
|
||||
<tr>
|
||||
{{#if invite.user}}
|
||||
<td>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<div class='autocomplete'>
|
||||
<ul>
|
||||
{{#each user in options.users}}
|
||||
{{#each options.users as |user|}}
|
||||
<li>
|
||||
<a href>
|
||||
{{avatar user imageSize="tiny"}}
|
||||
@ -10,7 +10,7 @@
|
||||
</li>
|
||||
{{/each}}
|
||||
{{#if options.groups}}
|
||||
{{#each group in options.groups}}
|
||||
{{#each options.groups as |group|}}
|
||||
<li>
|
||||
<a href>
|
||||
<i class='fa fa-users'></i>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{{#user-stream stream=model}}
|
||||
{{#each p in model.content}}
|
||||
{{#each model.content as |p|}}
|
||||
<div {{bind-attr class=":item p.hidden p.deleted p.moderator_action"}}>
|
||||
<div class="clearfix info">
|
||||
<a href="{{unbound p.usernameUrl}}" class="avatar-link">
|
||||
|
||||
@ -137,7 +137,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#each uf in userFields}}
|
||||
{{#each userFields as |uf|}}
|
||||
{{user-field field=uf.field value=uf.value}}
|
||||
{{/each}}
|
||||
<div class='clearfix'></div>
|
||||
|
||||
@ -8,7 +8,9 @@
|
||||
</li>
|
||||
<li>{{user-stat value=model.posts_read_count label="user.summary.posts_read"}}</li>
|
||||
<li>{{user-stat value=model.likes_given label="user.summary.likes_given"}}</li>
|
||||
<li>{{user-stat value=model.bookmark_count label="user.summary.bookmark_count"}}</li>
|
||||
{{#if model.bookmark_count}}
|
||||
<li>{{user-stat value=model.bookmark_count label="user.summary.bookmark_count"}}</li>
|
||||
{{/if}}
|
||||
<li>{{user-stat value=model.topic_count label="user.summary.topic_count"}}</li>
|
||||
<li>{{user-stat value=model.post_count label="user.summary.post_count"}}</li>
|
||||
<li>{{user-stat value=model.likes_received label="user.summary.likes_received"}}</li>
|
||||
@ -20,7 +22,7 @@
|
||||
<h3 class='stats-title'>{{i18n "user.summary.top_replies"}}</h3>
|
||||
{{#if model.replies.length}}
|
||||
<ul>
|
||||
{{#each reply in model.replies}}
|
||||
{{#each model.replies as |reply|}}
|
||||
<li>
|
||||
<span class='topic-info'>
|
||||
{{format-date reply.createdAt format="tiny" noTitle="true"}}
|
||||
@ -45,7 +47,7 @@
|
||||
<h3 class='stats-title'>{{i18n "user.summary.top_topics"}}</h3>
|
||||
{{#if model.topics.length}}
|
||||
<ul>
|
||||
{{#each topic in model.topics}}
|
||||
{{#each model.topics as |topic|}}
|
||||
<li>
|
||||
<span class='topic-info'>
|
||||
{{format-date topic.createdAt format="tiny" noTitle="true"}}
|
||||
@ -73,7 +75,7 @@
|
||||
<h3 class='stats-title'>{{i18n "user.summary.top_links"}}</h3>
|
||||
{{#if model.links.length}}
|
||||
<ul>
|
||||
{{#each link in model.links}}
|
||||
{{#each model.links as |link|}}
|
||||
<li>
|
||||
<a class='domain'
|
||||
href='{{unbound link.url}}'
|
||||
@ -93,14 +95,51 @@
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class='top-sub-section likes-section pull-right'>
|
||||
<h3 class='stats-title'>{{i18n "user.summary.most_replied_to_users"}}</h3>
|
||||
{{#if model.most_replied_to_users.length}}
|
||||
<ul>
|
||||
{{#each user in model.most_replied_to_users}}
|
||||
<li>
|
||||
{{#user-info user=user}}
|
||||
{{fa-icon "reply"}}
|
||||
<span class='replies'>{{user.count}}</span>
|
||||
{{/user-info}}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<p>{{i18n "user.summary.no_likes"}}</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='top-section'>
|
||||
<div class='top-sub-section likes-section pull-left'>
|
||||
<h3 class='stats-title'>{{i18n "user.summary.most_liked_by"}}</h3>
|
||||
{{#if model.most_liked_by_users.length}}
|
||||
<ul>
|
||||
{{#each user in model.most_liked_by_users}}
|
||||
{{#each model.most_liked_by_users as |user|}}
|
||||
<li>
|
||||
{{#user-info user=user}}
|
||||
{{fa-icon "heart"}}
|
||||
<span class='likes'>{{user.likes}}</span>
|
||||
<span class='likes'>{{user.count}}</span>
|
||||
{{/user-info}}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<p>{{i18n "user.summary.no_likes"}}</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class='top-sub-section likes-section pull-right'>
|
||||
<h3 class='stats-title'>{{i18n "user.summary.most_liked_users"}}</h3>
|
||||
{{#if model.most_liked_users.length}}
|
||||
<ul>
|
||||
{{#each user in model.most_liked_users}}
|
||||
<li>
|
||||
{{#user-info user=user}}
|
||||
{{fa-icon "heart"}}
|
||||
<span class='likes'>{{user.count}}</span>
|
||||
{{/user-info}}
|
||||
</li>
|
||||
{{/each}}
|
||||
@ -113,7 +152,7 @@
|
||||
|
||||
<div class='top-section badges-section'>
|
||||
<h3 class='stats-title'>{{i18n "user.summary.top_badges"}}</h3>
|
||||
{{#each badge in model.badges}}
|
||||
{{#each model.badges as |badge|}}
|
||||
{{badge-card badge=badge count=badge.count navigateOnClick="true" username=user.username_lower}}
|
||||
{{else}}
|
||||
<p>{{i18n "user.summary.no_badges"}}</p>
|
||||
|
||||
@ -88,7 +88,7 @@
|
||||
|
||||
{{#if publicUserFields}}
|
||||
<div class="public-user-fields">
|
||||
{{#each uf in publicUserFields}}
|
||||
{{#each publicUserFields as |uf|}}
|
||||
{{#if uf.value}}
|
||||
<div class="public-user-field {{uf.field.dasherized_name}}">
|
||||
<span class="user-field-name">{{uf.field.name}}</span>:
|
||||
@ -139,7 +139,7 @@
|
||||
{{#if model.displayGroups}}
|
||||
<dt>{{i18n 'groups.title' count=model.displayGroups.length}}</dt>
|
||||
<dd class='groups'>
|
||||
{{#each group in model.displayGroups}}
|
||||
{{#each model.displayGroups as |group|}}
|
||||
<span>{{#link-to 'group' group class="group-link"}}{{group.name}}{{/link-to}}</span>
|
||||
{{/each}}
|
||||
</dd>
|
||||
|
||||
@ -26,22 +26,8 @@
|
||||
{{/if}}
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each ic in model itemController="directory-item"}}
|
||||
<tr class="{{if ic.me 'me'}}">
|
||||
{{#with ic.model as |it|}}
|
||||
<td>{{user-info user=it.user}}</td>
|
||||
<td>{{number it.likes_received}}</td>
|
||||
<td>{{number it.likes_given}}</td>
|
||||
<td>{{number it.topic_count}}</td>
|
||||
<td>{{number it.post_count}}</td>
|
||||
<td>{{number it.topics_entered}}</td>
|
||||
<td>{{number it.posts_read}}</td>
|
||||
<td>{{number it.days_visited}}</td>
|
||||
{{#if controller.parentController.showTimeRead}}
|
||||
<td><span class='time-read'>{{unbound it.time_read}}</span></td>
|
||||
{{/if}}
|
||||
{{/with}}
|
||||
</tr>
|
||||
{{#each model as |item|}}
|
||||
{{directory-item item=item showTimeRead=showTimeRead}}
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -27,7 +27,7 @@ export default ContainerView.extend({
|
||||
}
|
||||
}
|
||||
|
||||
if (this.get('topic.details.can_invite_to')) {
|
||||
if (!mobileView && this.get('topic.details.can_invite_to')) {
|
||||
this.attachViewClass('invite-reply-button');
|
||||
}
|
||||
|
||||
|
||||
@ -229,11 +229,6 @@ export default createWidget('header', {
|
||||
togglePageSearch() {
|
||||
const { state } = this;
|
||||
|
||||
if (state.searchVisible) {
|
||||
this.toggleSearchMenu();
|
||||
return false;
|
||||
}
|
||||
|
||||
state.contextEnabled = false;
|
||||
|
||||
const currentPath = this.container.lookup('controller:application').get('currentPath');
|
||||
@ -248,6 +243,11 @@ export default createWidget('header', {
|
||||
this.container.lookup('controller:topic').get('model.postStream.stream.length'));
|
||||
}
|
||||
|
||||
if (state.searchVisible) {
|
||||
this.toggleSearchMenu();
|
||||
return showSearch;
|
||||
}
|
||||
|
||||
if (showSearch) {
|
||||
state.contextEnabled = true;
|
||||
this.toggleSearchMenu();
|
||||
|
||||
@ -48,7 +48,13 @@ export default createWidget('home-logo', {
|
||||
|
||||
click(e) {
|
||||
if (wantsNewWindow(e)) { return false; }
|
||||
|
||||
e.preventDefault();
|
||||
const a = $(e.target).closest('a')[0];
|
||||
if (a && a.host !== document.location.host) {
|
||||
document.location = a.href;
|
||||
}
|
||||
|
||||
DiscourseURL.routeTo(this.href());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -393,11 +393,13 @@ td.flaggers td {
|
||||
.setting-value {
|
||||
float: left;
|
||||
width: 53%;
|
||||
padding-right: 20px;
|
||||
.category-group {
|
||||
width: 95%;
|
||||
}
|
||||
@media (max-width: $mobile-breakpoint) {
|
||||
width: 100%;
|
||||
padding-right: 0;
|
||||
}
|
||||
.select2-container {
|
||||
width: 100% !important; // Needs !important to override hard-coded value
|
||||
@ -413,14 +415,14 @@ td.flaggers td {
|
||||
float: left;
|
||||
}
|
||||
.input-setting-string {
|
||||
width: 404px;
|
||||
@include medium-width { width: 314px; }
|
||||
box-sizing: border-box;
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
@media (max-width: $mobile-breakpoint) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.input-setting-list {
|
||||
width: 408px;
|
||||
@media (max-width: $mobile-breakpoint) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@ -23,7 +23,8 @@ class Admin::UsersController < Admin::AdminController
|
||||
:primary_group,
|
||||
:generate_api_key,
|
||||
:revoke_api_key,
|
||||
:anonymize]
|
||||
:anonymize,
|
||||
:reset_bounce_score]
|
||||
|
||||
def index
|
||||
users = ::AdminUserIndexQuery.new(params).find_users
|
||||
@ -355,6 +356,12 @@ class Admin::UsersController < Admin::AdminController
|
||||
end
|
||||
end
|
||||
|
||||
def reset_bounce_score
|
||||
guardian.ensure_can_reset_bounce_score!(@user)
|
||||
@user.user_stat.update_columns(bounce_score: 0, reset_bounce_score_after: nil)
|
||||
render json: success_json
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_user
|
||||
|
||||
@ -471,6 +471,7 @@ class UsersController < ApplicationController
|
||||
end
|
||||
|
||||
def account_created
|
||||
@custom_body_class = "static-account-created"
|
||||
@message = session['user_created_message'] || I18n.t('activation.missing_session')
|
||||
expires_now
|
||||
render layout: 'no_ember'
|
||||
|
||||
@ -173,10 +173,9 @@ module Jobs
|
||||
|
||||
if exceptions.length > 0
|
||||
exceptions.each do |exception_hash|
|
||||
Discourse.handle_job_exception(exception_hash[:ex],
|
||||
error_context(opts, exception_hash[:code], exception_hash[:other]))
|
||||
Discourse.handle_job_exception(exception_hash[:ex], error_context(opts, exception_hash[:code], exception_hash[:other]))
|
||||
end
|
||||
raise HandledExceptionWrapper.new exceptions[0][:ex]
|
||||
raise HandledExceptionWrapper.new(exceptions[0][:ex])
|
||||
end
|
||||
|
||||
nil
|
||||
|
||||
@ -2,7 +2,7 @@ module Jobs
|
||||
|
||||
class MigrateUploadScheme < Jobs::Onceoff
|
||||
|
||||
def execute(args)
|
||||
def execute_onceoff(args)
|
||||
return unless SiteSetting.migrate_to_new_scheme
|
||||
|
||||
# clean up failed uploads
|
||||
|
||||
@ -48,7 +48,24 @@ module Jobs
|
||||
@skip_context = { type: type, user_id: user_id, to_address: to_address, post_id: post_id }
|
||||
end
|
||||
|
||||
NOTIFICATIONS_SENT_BY_MAILING_LIST ||= Set.new %w{posted replied mentioned group_mentioned quoted}
|
||||
NOTIFICATIONS_SENT_BY_MAILING_LIST ||= Set.new %w{
|
||||
posted
|
||||
replied
|
||||
mentioned
|
||||
group_mentioned
|
||||
quoted
|
||||
}
|
||||
|
||||
CRITICAL_EMAIL_TYPES = Set.new %i{
|
||||
account_created
|
||||
admin_login
|
||||
confirm_new_email
|
||||
confirm_old_email
|
||||
forgot_password
|
||||
notify_old_email
|
||||
signup
|
||||
signup_after_approval
|
||||
}
|
||||
|
||||
def message_for_email(user, post, type, notification,
|
||||
notification_type=nil, notification_data_hash=nil,
|
||||
@ -109,7 +126,7 @@ module Jobs
|
||||
email_args[:email_token] = email_token
|
||||
end
|
||||
|
||||
if type == 'notify_old_email'
|
||||
if type == :notify_old_email
|
||||
email_args[:new_email] = user.email
|
||||
end
|
||||
|
||||
@ -117,7 +134,7 @@ module Jobs
|
||||
return skip_message(I18n.t('email_log.exceeded_emails_limit'))
|
||||
end
|
||||
|
||||
if (user.user_stat.try(:bounce_score) || 0) >= SiteSetting.bounce_score_threshold
|
||||
if !CRITICAL_EMAIL_TYPES.include?(type) && user.user_stat.bounce_score >= SiteSetting.bounce_score_threshold
|
||||
return skip_message(I18n.t('email_log.exceeded_bounces_limit'))
|
||||
end
|
||||
|
||||
@ -133,6 +150,22 @@ module Jobs
|
||||
[message, nil]
|
||||
end
|
||||
|
||||
sidekiq_retry_in do |count, exception|
|
||||
# retry in an hour when SMTP server is busy
|
||||
# or use default sidekiq retry formula
|
||||
case exception.wrapped
|
||||
when Net::SMTPServerBusy
|
||||
1.hour + (rand(30) * (count + 1))
|
||||
else
|
||||
Jobs::UserEmail.seconds_to_delay(count)
|
||||
end
|
||||
end
|
||||
|
||||
# extracted from sidekiq
|
||||
def self.seconds_to_delay(count)
|
||||
(count ** 4) + 15 + (rand(30) * (count + 1))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def skip_message(reason)
|
||||
|
||||
@ -30,7 +30,7 @@ module Jobs
|
||||
|
||||
set_incoming_email_rejection_message(
|
||||
receiver.incoming_email,
|
||||
I18n.t("email.incoming.errors.bounced_email_report")
|
||||
I18n.t("email.incoming.errors.bounced_email_error")
|
||||
)
|
||||
rescue Email::Receiver::AutoGeneratedEmailReplyError => e
|
||||
log_email_process_failure(mail_string, e)
|
||||
|
||||
@ -213,8 +213,8 @@ SQL
|
||||
|
||||
return unless opts[:message] && [:notify_moderators, :notify_user, :spam].include?(post_action_type)
|
||||
|
||||
title = I18n.t("post_action_types.#{post_action_type}.email_title", title: post.topic.title)
|
||||
body = I18n.t("post_action_types.#{post_action_type}.email_body", message: opts[:message], link: "#{Discourse.base_url}#{post.url}")
|
||||
title = I18n.t("post_action_types.#{post_action_type}.email_title", title: post.topic.title, locale: SiteSetting.default_locale)
|
||||
body = I18n.t("post_action_types.#{post_action_type}.email_body", message: opts[:message], link: "#{Discourse.base_url}#{post.url}", locale: SiteSetting.default_locale)
|
||||
warning = opts[:is_warning] if opts[:is_warning].present?
|
||||
title = title.truncate(255, separator: /\s/)
|
||||
|
||||
|
||||
@ -66,11 +66,8 @@ class Report
|
||||
ApplicationRequest.where(req_type: ApplicationRequest.req_types[filter])
|
||||
end
|
||||
|
||||
filtered_results = data
|
||||
filtered_results = data.filtered_results.where(category_id: report.category_id) if report.category_id
|
||||
|
||||
report.data = []
|
||||
filtered_results.where('date >= ? AND date <= ?', report.start_date.to_date, report.end_date.to_date)
|
||||
data.where('date >= ? AND date <= ?', report.start_date.to_date, report.end_date.to_date)
|
||||
.order(date: :asc)
|
||||
.group(:date)
|
||||
.sum(:count)
|
||||
@ -79,7 +76,7 @@ class Report
|
||||
end
|
||||
|
||||
report.total = data.sum(:count)
|
||||
report.prev30Days = filtered_results.where('date >= ? AND date <= ?',
|
||||
report.prev30Days = data.where('date >= ? AND date <= ?',
|
||||
(report.start_date - 31.days).to_date,
|
||||
(report.end_date - 31.days).to_date )
|
||||
.sum(:count)
|
||||
|
||||
@ -46,7 +46,7 @@ class UserSummary
|
||||
.limit(MAX_SUMMARY_RESULTS)
|
||||
end
|
||||
|
||||
class LikedByUser < OpenStruct
|
||||
class UserWithCount < OpenStruct
|
||||
include ActiveModel::SerializerSupport
|
||||
end
|
||||
|
||||
@ -65,20 +65,81 @@ class UserSummary
|
||||
User.where(id: likers.keys)
|
||||
.pluck(:id, :username, :name, :uploaded_avatar_id)
|
||||
.map do |u|
|
||||
LikedByUser.new(
|
||||
UserWithCount.new(
|
||||
id: u[0],
|
||||
username: u[1],
|
||||
name: u[2],
|
||||
avatar_template: User.avatar_template(u[1], u[3]),
|
||||
likes: likers[u[0].to_s]
|
||||
count: likers[u[0].to_s]
|
||||
)
|
||||
end.sort_by { |u| -u[:likes] }
|
||||
end.sort_by { |u| -u[:count] }
|
||||
end
|
||||
|
||||
def most_liked_users
|
||||
liked_users = {}
|
||||
UserAction.joins(:target_topic, :target_post)
|
||||
.where('topics.archetype <> ?', Archetype.private_message)
|
||||
.where(action_type: UserAction::WAS_LIKED)
|
||||
.where(acting_user_id: @user.id)
|
||||
.group(:user_id)
|
||||
.order('COUNT(*) DESC')
|
||||
.limit(MAX_SUMMARY_RESULTS)
|
||||
.pluck('user_actions.user_id, COUNT(*)')
|
||||
.each { |l| liked_users[l[0].to_s] = l[1] }
|
||||
|
||||
User.where(id: liked_users.keys)
|
||||
.pluck(:id, :username, :name, :uploaded_avatar_id)
|
||||
.map do |u|
|
||||
UserWithCount.new(
|
||||
id: u[0],
|
||||
username: u[1],
|
||||
name: u[2],
|
||||
avatar_template: User.avatar_template(u[1], u[3]),
|
||||
count: liked_users[u[0].to_s]
|
||||
)
|
||||
end.sort_by { |u| -u[:count] }
|
||||
end
|
||||
|
||||
REPLY_ACTIONS ||= [UserAction::RESPONSE, UserAction::QUOTE, UserAction::MENTION]
|
||||
|
||||
def most_replied_to_users
|
||||
replied_users = {}
|
||||
|
||||
Post
|
||||
.joins(:topic)
|
||||
.joins('JOIN posts replies ON posts.topic_id = replies.topic_id AND posts.reply_to_post_number = replies.post_number')
|
||||
.includes(:topic)
|
||||
.secured(@guardian)
|
||||
.merge(Topic.listable_topics.visible.secured(@guardian))
|
||||
.where(user: @user)
|
||||
.where('replies.user_id <> ?', @user.id)
|
||||
.group('replies.user_id')
|
||||
.order('COUNT(*) DESC')
|
||||
.limit(MAX_SUMMARY_RESULTS)
|
||||
.pluck('replies.user_id, COUNT(*)')
|
||||
.each { |r| replied_users[r[0].to_s] = r[1] }
|
||||
|
||||
User.where(id: replied_users.keys)
|
||||
.pluck(:id, :username, :name, :uploaded_avatar_id)
|
||||
.map do |u|
|
||||
UserWithCount.new(
|
||||
id: u[0],
|
||||
username: u[1],
|
||||
name: u[2],
|
||||
avatar_template: User.avatar_template(u[1], u[3]),
|
||||
count: replied_users[u[0].to_s]
|
||||
)
|
||||
end.sort_by { |u| -u[:count] }
|
||||
end
|
||||
|
||||
def badges
|
||||
@user.featured_user_badges(MAX_BADGES)
|
||||
end
|
||||
|
||||
def user_id
|
||||
@user.id
|
||||
end
|
||||
|
||||
def user_stat
|
||||
@user.user_stat
|
||||
end
|
||||
|
||||
@ -20,7 +20,9 @@ class AdminDetailedUserSerializer < AdminUserSerializer
|
||||
:primary_group_id,
|
||||
:badge_count,
|
||||
:warnings_received_count,
|
||||
:user_fields
|
||||
:user_fields,
|
||||
:bounce_score,
|
||||
:reset_bounce_score_after
|
||||
|
||||
has_one :approved_by, serializer: BasicUserSerializer, embed: :objects
|
||||
has_one :api_key, serializer: ApiKeySerializer, embed: :objects
|
||||
@ -76,4 +78,12 @@ class AdminDetailedUserSerializer < AdminUserSerializer
|
||||
object.user_fields.present?
|
||||
end
|
||||
|
||||
def bounce_score
|
||||
object.user_stat.bounce_score
|
||||
end
|
||||
|
||||
def reset_bounce_score_after
|
||||
object.user_stat.reset_bounce_score_after
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -18,14 +18,16 @@ class UserSummarySerializer < ApplicationSerializer
|
||||
end
|
||||
end
|
||||
|
||||
class MostLikedByUserSerializer < BasicUserSerializer
|
||||
attributes :likes, :name
|
||||
class UserWithCountSerializer < BasicUserSerializer
|
||||
attributes :count, :name
|
||||
end
|
||||
|
||||
has_many :topics, serializer: TopicSerializer
|
||||
has_many :replies, serializer: ReplySerializer, embed: :object
|
||||
has_many :links, serializer: LinkSerializer, embed: :object
|
||||
has_many :most_liked_by_users, serializer: MostLikedByUserSerializer, embed: :object
|
||||
has_many :most_liked_by_users, serializer: UserWithCountSerializer, embed: :object
|
||||
has_many :most_liked_users, serializer: UserWithCountSerializer, embed: :object
|
||||
has_many :most_replied_to_users, serializer: UserWithCountSerializer, embed: :object
|
||||
has_many :badges, serializer: UserBadgeSerializer, embed: :object
|
||||
|
||||
attributes :likes_given,
|
||||
@ -41,6 +43,10 @@ class UserSummarySerializer < ApplicationSerializer
|
||||
SiteSetting.enable_badges
|
||||
end
|
||||
|
||||
def include_bookmark_count?
|
||||
scope.authenticated? && object.user_id == scope.user.id
|
||||
end
|
||||
|
||||
def time_read
|
||||
AgeWords.age_words(object.time_read)
|
||||
end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user