DEV: Update admin models to native class syntax (#20704)

This commit was generated using the ember-native-class-codemod along with a handful of manual updates
This commit is contained in:
David Taylor 2023-03-17 10:18:42 +00:00 committed by GitHub
parent 303f97ce89
commit 64557c4076
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 684 additions and 766 deletions

View File

@ -7,19 +7,17 @@ const GENERAL_ATTRIBUTES = [
"release_notes_link", "release_notes_link",
]; ];
const AdminDashboard = EmberObject.extend({}); export default class AdminDashboard extends EmberObject {
static fetch() {
AdminDashboard.reopenClass({
fetch() {
return ajax("/admin/dashboard.json").then((json) => { return ajax("/admin/dashboard.json").then((json) => {
const model = AdminDashboard.create(); const model = AdminDashboard.create();
model.set("version_check", json.version_check); model.set("version_check", json.version_check);
return model; return model;
}); });
}, }
fetchGeneral() { static fetchGeneral() {
return ajax("/admin/dashboard/general.json").then((json) => { return ajax("/admin/dashboard/general.json").then((json) => {
const model = AdminDashboard.create(); const model = AdminDashboard.create();
@ -34,15 +32,13 @@ AdminDashboard.reopenClass({
return model; return model;
}); });
}, }
fetchProblems() { static fetchProblems() {
return ajax("/admin/dashboard/problems.json").then((json) => { return ajax("/admin/dashboard/problems.json").then((json) => {
const model = AdminDashboard.create(json); const model = AdminDashboard.create(json);
model.set("loaded", true); model.set("loaded", true);
return model; return model;
}); });
}, }
}); }
export default AdminDashboard;

View File

@ -10,14 +10,30 @@ import { popupAjaxError } from "discourse/lib/ajax-error";
import { propertyNotEqual } from "discourse/lib/computed"; import { propertyNotEqual } from "discourse/lib/computed";
import { userPath } from "discourse/lib/url"; import { userPath } from "discourse/lib/url";
const wrapAdmin = (user) => (user ? AdminUser.create(user) : null); export default class AdminUser extends User {
static find(user_id) {
return ajax(`/admin/users/${user_id}.json`).then((result) => {
result.loadedDetails = true;
return AdminUser.create(result);
});
}
const AdminUser = User.extend({ static findAll(query, userFilter) {
adminUserView: true, return ajax(`/admin/users/list/${query}.json`, {
customGroups: filter("groups", (g) => !g.automatic && Group.create(g)), data: userFilter,
automaticGroups: filter("groups", (g) => g.automatic && Group.create(g)), }).then((users) => users.map((u) => AdminUser.create(u)));
}
canViewProfile: or("active", "staged"), adminUserView = true;
@filter("groups", (g) => !g.automatic && Group.create(g)) customGroups;
@filter("groups", (g) => g.automatic && Group.create(g)) automaticGroups;
@or("active", "staged") canViewProfile;
@gt("bounce_score", 0) canResetBounceScore;
@propertyNotEqual("originalTrustLevel", "trust_level") dirty;
@lt("trust_level", 4) canLockTrustLevel;
@not("staff") canSuspend;
@not("staff") canSilence;
@discourseComputed("bounce_score", "reset_bounce_score_after") @discourseComputed("bounce_score", "reset_bounce_score_after")
bounceScore(bounce_score, reset_bounce_score_after) { bounceScore(bounce_score, reset_bounce_score_after) {
@ -28,7 +44,7 @@ const AdminUser = User.extend({
} else { } else {
return bounce_score; return bounce_score;
} }
}, }
@discourseComputed("bounce_score") @discourseComputed("bounce_score")
bounceScoreExplanation(bounce_score) { bounceScoreExplanation(bounce_score) {
@ -39,14 +55,12 @@ const AdminUser = User.extend({
} else { } else {
return I18n.t("admin.user.bounce_score_explanation.threshold_reached"); return I18n.t("admin.user.bounce_score_explanation.threshold_reached");
} }
}, }
@discourseComputed @discourseComputed
bounceLink() { bounceLink() {
return getURL("/admin/email/bounced"); return getURL("/admin/email/bounced");
}, }
canResetBounceScore: gt("bounce_score", 0),
resetBounceScore() { resetBounceScore() {
return ajax(`/admin/users/${this.id}/reset_bounce_score`, { return ajax(`/admin/users/${this.id}/reset_bounce_score`, {
@ -57,14 +71,14 @@ const AdminUser = User.extend({
reset_bounce_score_after: null, reset_bounce_score_after: null,
}) })
); );
}, }
groupAdded(added) { groupAdded(added) {
return ajax(`/admin/users/${this.id}/groups`, { return ajax(`/admin/users/${this.id}/groups`, {
type: "POST", type: "POST",
data: { group_id: added.id }, data: { group_id: added.id },
}).then(() => this.groups.pushObject(added)); }).then(() => this.groups.pushObject(added));
}, }
groupRemoved(groupId) { groupRemoved(groupId) {
return ajax(`/admin/users/${this.id}/groups/${groupId}`, { return ajax(`/admin/users/${this.id}/groups/${groupId}`, {
@ -75,13 +89,13 @@ const AdminUser = User.extend({
this.set("primary_group_id", null); this.set("primary_group_id", null);
} }
}); });
}, }
deleteAllPosts() { deleteAllPosts() {
return ajax(`/admin/users/${this.get("id")}/delete_posts_batch`, { return ajax(`/admin/users/${this.get("id")}/delete_posts_batch`, {
type: "PUT", type: "PUT",
}); });
}, }
revokeAdmin() { revokeAdmin() {
return ajax(`/admin/users/${this.id}/revoke_admin`, { return ajax(`/admin/users/${this.id}/revoke_admin`, {
@ -97,7 +111,7 @@ const AdminUser = User.extend({
can_delete_all_posts: resp.can_delete_all_posts, can_delete_all_posts: resp.can_delete_all_posts,
}); });
}); });
}, }
grantAdmin(data) { grantAdmin(data) {
return ajax(`/admin/users/${this.id}/grant_admin`, { return ajax(`/admin/users/${this.id}/grant_admin`, {
@ -114,7 +128,7 @@ const AdminUser = User.extend({
return resp; return resp;
}); });
}, }
revokeModeration() { revokeModeration() {
return ajax(`/admin/users/${this.id}/revoke_moderation`, { return ajax(`/admin/users/${this.id}/revoke_moderation`, {
@ -130,7 +144,7 @@ const AdminUser = User.extend({
}); });
}) })
.catch(popupAjaxError); .catch(popupAjaxError);
}, }
grantModeration() { grantModeration() {
return ajax(`/admin/users/${this.id}/grant_moderation`, { return ajax(`/admin/users/${this.id}/grant_moderation`, {
@ -146,7 +160,7 @@ const AdminUser = User.extend({
}); });
}) })
.catch(popupAjaxError); .catch(popupAjaxError);
}, }
disableSecondFactor() { disableSecondFactor() {
return ajax(`/admin/users/${this.id}/disable_second_factor`, { return ajax(`/admin/users/${this.id}/disable_second_factor`, {
@ -156,7 +170,7 @@ const AdminUser = User.extend({
this.set("second_factor_enabled", false); this.set("second_factor_enabled", false);
}) })
.catch(popupAjaxError); .catch(popupAjaxError);
}, }
approve(approvedBy) { approve(approvedBy) {
return ajax(`/admin/users/${this.id}/approve`, { return ajax(`/admin/users/${this.id}/approve`, {
@ -168,83 +182,76 @@ const AdminUser = User.extend({
approved_by: approvedBy, approved_by: approvedBy,
}); });
}); });
}, }
setOriginalTrustLevel() { setOriginalTrustLevel() {
this.set("originalTrustLevel", this.trust_level); this.set("originalTrustLevel", this.trust_level);
}, }
dirty: propertyNotEqual("originalTrustLevel", "trust_level"),
saveTrustLevel() { saveTrustLevel() {
return ajax(`/admin/users/${this.id}/trust_level`, { return ajax(`/admin/users/${this.id}/trust_level`, {
type: "PUT", type: "PUT",
data: { level: this.trust_level }, data: { level: this.trust_level },
}); });
}, }
restoreTrustLevel() { restoreTrustLevel() {
this.set("trust_level", this.originalTrustLevel); this.set("trust_level", this.originalTrustLevel);
}, }
lockTrustLevel(locked) { lockTrustLevel(locked) {
return ajax(`/admin/users/${this.id}/trust_level_lock`, { return ajax(`/admin/users/${this.id}/trust_level_lock`, {
type: "PUT", type: "PUT",
data: { locked: !!locked }, data: { locked: !!locked },
}); });
}, }
canLockTrustLevel: lt("trust_level", 4),
canSuspend: not("staff"),
canSilence: not("staff"),
@discourseComputed("suspended_till", "suspended_at") @discourseComputed("suspended_till", "suspended_at")
suspendDuration(suspendedTill, suspendedAt) { suspendDuration(suspendedTill, suspendedAt) {
suspendedAt = moment(suspendedAt); suspendedAt = moment(suspendedAt);
suspendedTill = moment(suspendedTill); suspendedTill = moment(suspendedTill);
return suspendedAt.format("L") + " - " + suspendedTill.format("L"); return suspendedAt.format("L") + " - " + suspendedTill.format("L");
}, }
suspend(data) { suspend(data) {
return ajax(`/admin/users/${this.id}/suspend`, { return ajax(`/admin/users/${this.id}/suspend`, {
type: "PUT", type: "PUT",
data, data,
}).then((result) => this.setProperties(result.suspension)); }).then((result) => this.setProperties(result.suspension));
}, }
unsuspend() { unsuspend() {
return ajax(`/admin/users/${this.id}/unsuspend`, { return ajax(`/admin/users/${this.id}/unsuspend`, {
type: "PUT", type: "PUT",
}).then((result) => this.setProperties(result.suspension)); }).then((result) => this.setProperties(result.suspension));
}, }
logOut() { logOut() {
return ajax("/admin/users/" + this.id + "/log_out", { return ajax("/admin/users/" + this.id + "/log_out", {
type: "POST", type: "POST",
data: { username_or_email: this.username }, data: { username_or_email: this.username },
}); });
}, }
impersonate() { impersonate() {
return ajax("/admin/impersonate", { return ajax("/admin/impersonate", {
type: "POST", type: "POST",
data: { username_or_email: this.username }, data: { username_or_email: this.username },
}); });
}, }
activate() { activate() {
return ajax(`/admin/users/${this.id}/activate`, { return ajax(`/admin/users/${this.id}/activate`, {
type: "PUT", type: "PUT",
}); });
}, }
deactivate() { deactivate() {
return ajax(`/admin/users/${this.id}/deactivate`, { return ajax(`/admin/users/${this.id}/deactivate`, {
type: "PUT", type: "PUT",
data: { context: document.location.pathname }, data: { context: document.location.pathname },
}); });
}, }
unsilence() { unsilence() {
this.set("silencingUser", true); this.set("silencingUser", true);
@ -254,7 +261,7 @@ const AdminUser = User.extend({
}) })
.then((result) => this.setProperties(result.unsilence)) .then((result) => this.setProperties(result.unsilence))
.finally(() => this.set("silencingUser", false)); .finally(() => this.set("silencingUser", false));
}, }
silence(data) { silence(data) {
this.set("silencingUser", true); this.set("silencingUser", true);
@ -265,20 +272,20 @@ const AdminUser = User.extend({
}) })
.then((result) => this.setProperties(result.silence)) .then((result) => this.setProperties(result.silence))
.finally(() => this.set("silencingUser", false)); .finally(() => this.set("silencingUser", false));
}, }
sendActivationEmail() { sendActivationEmail() {
return ajax(userPath("action/send_activation_email"), { return ajax(userPath("action/send_activation_email"), {
type: "POST", type: "POST",
data: { username: this.username }, data: { username: this.username },
}); });
}, }
anonymize() { anonymize() {
return ajax(`/admin/users/${this.id}/anonymize.json`, { return ajax(`/admin/users/${this.id}/anonymize.json`, {
type: "PUT", type: "PUT",
}); });
}, }
destroy(formData) { destroy(formData) {
return ajax(`/admin/users/${this.id}.json`, { return ajax(`/admin/users/${this.id}.json`, {
@ -295,14 +302,14 @@ const AdminUser = User.extend({
.catch(() => { .catch(() => {
this.find(this.id).then((u) => this.setProperties(u)); this.find(this.id).then((u) => this.setProperties(u));
}); });
}, }
merge(formData) { merge(formData) {
return ajax(`/admin/users/${this.id}/merge.json`, { return ajax(`/admin/users/${this.id}/merge.json`, {
type: "POST", type: "POST",
data: formData, data: formData,
}); });
}, }
loadDetails() { loadDetails() {
if (this.loadedDetails) { if (this.loadedDetails) {
@ -313,23 +320,29 @@ const AdminUser = User.extend({
const userProperties = Object.assign(result, { loadedDetails: true }); const userProperties = Object.assign(result, { loadedDetails: true });
this.setProperties(userProperties); this.setProperties(userProperties);
}); });
}, }
@discourseComputed("tl3_requirements") @discourseComputed("tl3_requirements")
tl3Requirements(requirements) { tl3Requirements(requirements) {
if (requirements) { if (requirements) {
return this.store.createRecord("tl3Requirements", requirements); return this.store.createRecord("tl3Requirements", requirements);
} }
}, }
@discourseComputed("suspended_by") @discourseComputed("suspended_by")
suspendedBy: wrapAdmin, suspendedBy(user) {
return user ? AdminUser.create(user) : null;
}
@discourseComputed("silenced_by") @discourseComputed("silenced_by")
silencedBy: wrapAdmin, silencedBy(user) {
return user ? AdminUser.create(user) : null;
}
@discourseComputed("approved_by") @discourseComputed("approved_by")
approvedBy: wrapAdmin, approvedBy(user) {
return user ? AdminUser.create(user) : null;
}
deleteSSORecord() { deleteSSORecord() {
return ajax(`/admin/users/${this.id}/sso_record.json`, { return ajax(`/admin/users/${this.id}/sso_record.json`, {
@ -339,22 +352,5 @@ const AdminUser = User.extend({
this.set("single_sign_on_record", null); this.set("single_sign_on_record", null);
}) })
.catch(popupAjaxError); .catch(popupAjaxError);
}, }
}); }
AdminUser.reopenClass({
find(user_id) {
return ajax(`/admin/users/${user_id}.json`).then((result) => {
result.loadedDetails = true;
return AdminUser.create(result);
});
},
findAll(query, userFilter) {
return ajax(`/admin/users/list/${query}.json`, {
data: userFilter,
}).then((users) => users.map((u) => AdminUser.create(u)));
},
});
export default AdminUser;

View File

@ -1,24 +1,26 @@
import { computed } from "@ember/object";
import AdminUser from "admin/models/admin-user"; import AdminUser from "admin/models/admin-user";
import RestModel from "discourse/models/rest"; import RestModel from "discourse/models/rest";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { computed } from "@ember/object";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import { fmt } from "discourse/lib/computed"; import { fmt } from "discourse/lib/computed";
const ApiKey = RestModel.extend({ export default class ApiKey extends RestModel {
user: computed("_user", { @fmt("truncated_key", "%@...") truncatedKey;
get() {
@computed("_user")
get user() {
return this._user; return this._user;
}, }
set(key, value) {
set user(value) {
if (value && !(value instanceof AdminUser)) { if (value && !(value instanceof AdminUser)) {
this.set("_user", AdminUser.create(value)); this.set("_user", AdminUser.create(value));
} else { } else {
this.set("_user", value); this.set("_user", value);
} }
return this._user; return this._user;
}, }
}),
@discourseComputed("description") @discourseComputed("description")
shortDescription(description) { shortDescription(description) {
@ -26,32 +28,28 @@ const ApiKey = RestModel.extend({
return description; return description;
} }
return `${description.substring(0, 40)}...`; return `${description.substring(0, 40)}...`;
}, }
truncatedKey: fmt("truncated_key", "%@..."),
revoke() { revoke() {
return ajax(`${this.basePath}/revoke`, { return ajax(`${this.basePath}/revoke`, {
type: "POST", type: "POST",
}).then((result) => this.setProperties(result.api_key)); }).then((result) => this.setProperties(result.api_key));
}, }
undoRevoke() { undoRevoke() {
return ajax(`${this.basePath}/undo-revoke`, { return ajax(`${this.basePath}/undo-revoke`, {
type: "POST", type: "POST",
}).then((result) => this.setProperties(result.api_key)); }).then((result) => this.setProperties(result.api_key));
}, }
createProperties() { createProperties() {
return this.getProperties("description", "username", "scopes"); return this.getProperties("description", "username", "scopes");
}, }
@discourseComputed() @discourseComputed()
basePath() { basePath() {
return this.store return this.store
.adapterFor("api-key") .adapterFor("api-key")
.pathFor(this.store, "api-key", this.id); .pathFor(this.store, "api-key", this.id);
}, }
}); }
export default ApiKey;

View File

@ -1,12 +1,12 @@
import { not } from "@ember/object/computed";
import EmberObject from "@ember/object"; import EmberObject from "@ember/object";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import { not } from "@ember/object/computed";
export default EmberObject.extend({ export default class BackupStatus extends EmberObject {
restoreDisabled: not("restoreEnabled"), @not("restoreEnabled") restoreDisabled;
@discourseComputed("allowRestore", "isOperationRunning") @discourseComputed("allowRestore", "isOperationRunning")
restoreEnabled(allowRestore, isOperationRunning) { restoreEnabled(allowRestore, isOperationRunning) {
return allowRestore && !isOperationRunning; return allowRestore && !isOperationRunning;
}, }
}); }

View File

@ -2,25 +2,12 @@ import EmberObject from "@ember/object";
import MessageBus from "message-bus-client"; import MessageBus from "message-bus-client";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
const Backup = EmberObject.extend({ export default class Backup extends EmberObject {
destroy() { static find() {
return ajax("/admin/backups/" + this.filename, { type: "DELETE" });
},
restore() {
return ajax("/admin/backups/" + this.filename + "/restore", {
type: "POST",
data: { client_id: MessageBus.clientId },
});
},
});
Backup.reopenClass({
find() {
return ajax("/admin/backups.json"); return ajax("/admin/backups.json");
}, }
start(withUploads) { static start(withUploads) {
if (withUploads === undefined) { if (withUploads === undefined) {
withUploads = true; withUploads = true;
} }
@ -31,19 +18,28 @@ Backup.reopenClass({
client_id: MessageBus.clientId, client_id: MessageBus.clientId,
}, },
}); });
}, }
cancel() { static cancel() {
return ajax("/admin/backups/cancel.json", { return ajax("/admin/backups/cancel.json", {
type: "DELETE", type: "DELETE",
}); });
}, }
rollback() { static rollback() {
return ajax("/admin/backups/rollback.json", { return ajax("/admin/backups/rollback.json", {
type: "POST", type: "POST",
}); });
}, }
});
export default Backup; destroy() {
return ajax("/admin/backups/" + this.filename, { type: "DELETE" });
}
restore() {
return ajax("/admin/backups/" + this.filename + "/restore", {
type: "POST",
data: { client_id: MessageBus.clientId },
});
}
}

View File

@ -1,19 +1,19 @@
import discourseComputed, { import discourseComputed from "discourse-common/utils/decorators";
observes, import { observes, on } from "@ember-decorators/object";
on,
} from "discourse-common/utils/decorators";
import EmberObject from "@ember/object"; import EmberObject from "@ember/object";
import I18n from "I18n"; import I18n from "I18n";
import { propertyNotEqual } from "discourse/lib/computed"; import { propertyNotEqual } from "discourse/lib/computed";
const ColorSchemeColor = EmberObject.extend({ export default class ColorSchemeColor extends EmberObject {
// Whether the current value is different than Discourse's default color scheme.
@propertyNotEqual("hex", "default_hex") overridden;
@on("init") @on("init")
startTrackingChanges() { startTrackingChanges() {
this.set("originals", { hex: this.hex || "FFFFFF" }); this.set("originals", { hex: this.hex || "FFFFFF" });
// force changed property to be recalculated // force changed property to be recalculated
this.notifyPropertyChange("hex"); this.notifyPropertyChange("hex");
}, }
// Whether value has changed since it was last saved. // Whether value has changed since it was last saved.
@discourseComputed("hex") @discourseComputed("hex")
@ -26,26 +26,23 @@ const ColorSchemeColor = EmberObject.extend({
} }
return false; return false;
}, }
// Whether the current value is different than Discourse's default color scheme.
overridden: propertyNotEqual("hex", "default_hex"),
// Whether the saved value is different than Discourse's default color scheme. // Whether the saved value is different than Discourse's default color scheme.
@discourseComputed("default_hex", "hex") @discourseComputed("default_hex", "hex")
savedIsOverriden(defaultHex) { savedIsOverriden(defaultHex) {
return this.originals.hex !== defaultHex; return this.originals.hex !== defaultHex;
}, }
revert() { revert() {
this.set("hex", this.default_hex); this.set("hex", this.default_hex);
}, }
undo() { undo() {
if (this.originals) { if (this.originals) {
this.set("hex", this.originals.hex); this.set("hex", this.originals.hex);
} }
}, }
@discourseComputed("name") @discourseComputed("name")
translatedName(name) { translatedName(name) {
@ -54,7 +51,7 @@ const ColorSchemeColor = EmberObject.extend({
} else { } else {
return name; return name;
} }
}, }
@discourseComputed("name") @discourseComputed("name")
description(name) { description(name) {
@ -63,7 +60,7 @@ const ColorSchemeColor = EmberObject.extend({
} else { } else {
return ""; return "";
} }
}, }
/** /**
brightness returns a number between 0 (darkest) to 255 (brightest). brightness returns a number between 0 (darkest) to 255 (brightest).
@ -90,19 +87,17 @@ const ColorSchemeColor = EmberObject.extend({
1000 1000
); );
} }
}, }
@observes("hex") @observes("hex")
hexValueChanged() { hexValueChanged() {
if (this.hex) { if (this.hex) {
this.set("hex", this.hex.toString().replace(/[^0-9a-fA-F]/g, "")); this.set("hex", this.hex.toString().replace(/[^0-9a-fA-F]/g, ""));
} }
}, }
@discourseComputed("hex") @discourseComputed("hex")
valid(hex) { valid(hex) {
return hex.match(/^([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/) !== null; return hex.match(/^([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/) !== null;
}, }
}); }
export default ColorSchemeColor;

View File

@ -1,3 +1,4 @@
import { not } from "@ember/object/computed";
import { A } from "@ember/array"; import { A } from "@ember/array";
import ArrayProxy from "@ember/array/proxy"; import ArrayProxy from "@ember/array/proxy";
import ColorSchemeColor from "admin/models/color-scheme-color"; import ColorSchemeColor from "admin/models/color-scheme-color";
@ -5,26 +6,56 @@ import EmberObject from "@ember/object";
import I18n from "I18n"; import I18n from "I18n";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import { not } from "@ember/object/computed";
const ColorScheme = EmberObject.extend({ class ColorSchemes extends ArrayProxy {}
export default class ColorScheme extends EmberObject {
static findAll() {
const colorSchemes = ColorSchemes.create({ content: [], loading: true });
return ajax("/admin/color_schemes").then((all) => {
all.forEach((colorScheme) => {
colorSchemes.pushObject(
ColorScheme.create({
id: colorScheme.id,
name: colorScheme.name,
is_base: colorScheme.is_base,
theme_id: colorScheme.theme_id,
theme_name: colorScheme.theme_name,
base_scheme_id: colorScheme.base_scheme_id,
user_selectable: colorScheme.user_selectable,
colors: colorScheme.colors.map((c) => {
return ColorSchemeColor.create({
name: c.name,
hex: c.hex,
default_hex: c.default_hex,
is_advanced: c.is_advanced,
});
}),
})
);
});
return colorSchemes;
});
}
@not("id") newRecord;
init() { init() {
this._super(...arguments); super.init(...arguments);
this.startTrackingChanges(); this.startTrackingChanges();
}, }
@discourseComputed @discourseComputed
description() { description() {
return "" + this.name; return "" + this.name;
}, }
startTrackingChanges() { startTrackingChanges() {
this.set("originals", { this.set("originals", {
name: this.name, name: this.name,
user_selectable: this.user_selectable, user_selectable: this.user_selectable,
}); });
}, }
schemeJson() { schemeJson() {
const buffer = []; const buffer = [];
@ -33,7 +64,7 @@ const ColorScheme = EmberObject.extend({
}); });
return [`"${this.name}": {`, buffer.join(",\n"), "}"].join("\n"); return [`"${this.name}": {`, buffer.join(",\n"), "}"].join("\n");
}, }
copy() { copy() {
const newScheme = ColorScheme.create({ const newScheme = ColorScheme.create({
@ -47,7 +78,7 @@ const ColorScheme = EmberObject.extend({
); );
}); });
return newScheme; return newScheme;
}, }
@discourseComputed( @discourseComputed(
"name", "name",
@ -70,7 +101,7 @@ const ColorScheme = EmberObject.extend({
} }
return false; return false;
}, }
@discourseComputed("changed") @discourseComputed("changed")
disableSave(changed) { disableSave(changed) {
@ -79,9 +110,7 @@ const ColorScheme = EmberObject.extend({
} }
return !changed || this.saving || this.colors.any((c) => !c.get("valid")); return !changed || this.saving || this.colors.any((c) => !c.get("valid"));
}, }
newRecord: not("id"),
save(opts) { save(opts) {
if (this.is_base || this.disableSave) { if (this.is_base || this.disableSave) {
@ -124,7 +153,7 @@ const ColorScheme = EmberObject.extend({
this.setProperties({ savingStatus: I18n.t("saved"), saving: false }); this.setProperties({ savingStatus: I18n.t("saved"), saving: false });
this.notifyPropertyChange("description"); this.notifyPropertyChange("description");
}); });
}, }
updateUserSelectable(value) { updateUserSelectable(value) {
if (!this.id) { if (!this.id) {
@ -137,45 +166,11 @@ const ColorScheme = EmberObject.extend({
dataType: "json", dataType: "json",
contentType: "application/json", contentType: "application/json",
}); });
}, }
destroy() { destroy() {
if (this.id) { if (this.id) {
return ajax(`/admin/color_schemes/${this.id}`, { type: "DELETE" }); return ajax(`/admin/color_schemes/${this.id}`, { type: "DELETE" });
} }
}, }
}); }
const ColorSchemes = ArrayProxy.extend({});
ColorScheme.reopenClass({
findAll() {
const colorSchemes = ColorSchemes.create({ content: [], loading: true });
return ajax("/admin/color_schemes").then((all) => {
all.forEach((colorScheme) => {
colorSchemes.pushObject(
ColorScheme.create({
id: colorScheme.id,
name: colorScheme.name,
is_base: colorScheme.is_base,
theme_id: colorScheme.theme_id,
theme_name: colorScheme.theme_name,
base_scheme_id: colorScheme.base_scheme_id,
user_selectable: colorScheme.user_selectable,
colors: colorScheme.colors.map((c) => {
return ColorSchemeColor.create({
name: c.name,
hex: c.hex,
default_hex: c.default_hex,
is_advanced: c.is_advanced,
});
}),
})
);
});
return colorSchemes;
});
},
});
export default ColorScheme;

View File

@ -3,10 +3,8 @@ import EmberObject from "@ember/object";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import getURL from "discourse-common/lib/get-url"; import getURL from "discourse-common/lib/get-url";
const EmailLog = EmberObject.extend({}); export default class EmailLog extends EmberObject {
static create(attrs) {
EmailLog.reopenClass({
create(attrs) {
attrs = attrs || {}; attrs = attrs || {};
if (attrs.user) { if (attrs.user) {
@ -17,10 +15,10 @@ EmailLog.reopenClass({
attrs.post_url = getURL(attrs.post_url); attrs.post_url = getURL(attrs.post_url);
} }
return this._super(attrs); return super.create(attrs);
}, }
findAll(filter, offset) { static findAll(filter, offset) {
filter = filter || {}; filter = filter || {};
offset = offset || 0; offset = offset || 0;
@ -30,7 +28,5 @@ EmailLog.reopenClass({
return ajax(`/admin/email/${status}.json?offset=${offset}`, { return ajax(`/admin/email/${status}.json?offset=${offset}`, {
data: filter, data: filter,
}).then((logs) => logs.map((log) => EmailLog.create(log))); }).then((logs) => logs.map((log) => EmailLog.create(log)));
}, }
}); }
export default EmailLog;

View File

@ -1,25 +1,21 @@
import EmberObject from "@ember/object"; import EmberObject from "@ember/object";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
const EmailPreview = EmberObject.extend({}); export default class EmailPreview extends EmberObject {
static findDigest(username, lastSeenAt) {
export function oneWeekAgo() {
return moment().locale("en").subtract(7, "days").format("YYYY-MM-DD");
}
EmailPreview.reopenClass({
findDigest(username, lastSeenAt) {
return ajax("/admin/email/preview-digest.json", { return ajax("/admin/email/preview-digest.json", {
data: { last_seen_at: lastSeenAt || oneWeekAgo(), username }, data: { last_seen_at: lastSeenAt || oneWeekAgo(), username },
}).then((result) => EmailPreview.create(result)); }).then((result) => EmailPreview.create(result));
}, }
sendDigest(username, lastSeenAt, email) { static sendDigest(username, lastSeenAt, email) {
return ajax("/admin/email/send-digest.json", { return ajax("/admin/email/send-digest.json", {
type: "POST", type: "POST",
data: { last_seen_at: lastSeenAt || oneWeekAgo(), username, email }, data: { last_seen_at: lastSeenAt || oneWeekAgo(), username, email },
}); });
}, }
}); }
export default EmailPreview; export function oneWeekAgo() {
return moment().locale("en").subtract(7, "days").format("YYYY-MM-DD");
}

View File

@ -1,14 +1,10 @@
import EmberObject from "@ember/object"; import EmberObject from "@ember/object";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
const EmailSettings = EmberObject.extend({}); export default class EmailSettings extends EmberObject {
static find() {
EmailSettings.reopenClass({
find() {
return ajax("/admin/email.json").then(function (settings) { return ajax("/admin/email.json").then(function (settings) {
return EmailSettings.create(settings); return EmailSettings.create(settings);
}); });
}, }
}); }
export default EmailSettings;

View File

@ -1,10 +1,10 @@
import RestModel from "discourse/models/rest"; import RestModel from "discourse/models/rest";
export default RestModel.extend({ export default class EmailStyle extends RestModel {
changed: false, changed = false;
setField(fieldName, value) { setField(fieldName, value) {
this.set(`${fieldName}`, value); this.set(`${fieldName}`, value);
this.set("changed", true); this.set("changed", true);
}, }
}); }

View File

@ -2,12 +2,12 @@ import RestModel from "discourse/models/rest";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { getProperties } from "@ember/object"; import { getProperties } from "@ember/object";
export default RestModel.extend({ export default class EmailTemplate extends RestModel {
revert() { revert() {
return ajax(`/admin/customize/email_templates/${this.id}`, { return ajax(`/admin/customize/email_templates/${this.id}`, {
type: "DELETE", type: "DELETE",
}).then((result) => }).then((result) =>
getProperties(result.email_template, "subject", "body", "can_revert") getProperties(result.email_template, "subject", "body", "can_revert")
); );
}, }
}); }

View File

@ -2,9 +2,9 @@ import I18n from "I18n";
import RestModel from "discourse/models/rest"; import RestModel from "discourse/models/rest";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
export default RestModel.extend({ export default class FlagType extends RestModel {
@discourseComputed("id") @discourseComputed("id")
name(id) { name(id) {
return I18n.t(`admin.flags.summary.action_type_${id}`, { count: 1 }); return I18n.t(`admin.flags.summary.action_type_${id}`, { count: 1 });
}, }
}); }

View File

@ -1,53 +1,51 @@
import RestModel from "discourse/models/rest"; import RestModel from "discourse/models/rest";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
export default class FormTemplate extends RestModel {} export default class FormTemplate extends RestModel {
static createTemplate(data) {
FormTemplate.reopenClass({
createTemplate(data) {
return ajax("/admin/customize/form-templates.json", { return ajax("/admin/customize/form-templates.json", {
type: "POST", type: "POST",
data, data,
}); });
}, }
updateTemplate(id, data) { static updateTemplate(id, data) {
return ajax(`/admin/customize/form-templates/${id}.json`, { return ajax(`/admin/customize/form-templates/${id}.json`, {
type: "PUT", type: "PUT",
data, data,
}); });
}, }
createOrUpdateTemplate(data) { static createOrUpdateTemplate(data) {
if (data.id) { if (data.id) {
return this.updateTemplate(data.id, data); return this.updateTemplate(data.id, data);
} else { } else {
return this.createTemplate(data); return this.createTemplate(data);
} }
}, }
deleteTemplate(id) { static deleteTemplate(id) {
return ajax(`/admin/customize/form-templates/${id}.json`, { return ajax(`/admin/customize/form-templates/${id}.json`, {
type: "DELETE", type: "DELETE",
}); });
}, }
findAll() { static findAll() {
return ajax(`/admin/customize/form-templates.json`).then((model) => { return ajax(`/admin/customize/form-templates.json`).then((model) => {
return model.form_templates.sort((a, b) => a.id - b.id); return model.form_templates.sort((a, b) => a.id - b.id);
}); });
}, }
findById(id) { static findById(id) {
return ajax(`/admin/customize/form-templates/${id}.json`).then((model) => { return ajax(`/admin/customize/form-templates/${id}.json`).then((model) => {
return model.form_template; return model.form_template;
}); });
}, }
validateTemplate(data) { static validateTemplate(data) {
return ajax(`/admin/customize/form-templates/preview.json`, { return ajax(`/admin/customize/form-templates/preview.json`, {
type: "GET", type: "GET",
data, data,
}); });
}, }
}); }

View File

@ -2,10 +2,8 @@ import AdminUser from "admin/models/admin-user";
import EmberObject from "@ember/object"; import EmberObject from "@ember/object";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
const IncomingEmail = EmberObject.extend({}); export default class IncomingEmail extends EmberObject {
static create(attrs) {
IncomingEmail.reopenClass({
create(attrs) {
attrs = attrs || {}; attrs = attrs || {};
if (attrs.user) { if (attrs.user) {
@ -13,17 +11,17 @@ IncomingEmail.reopenClass({
} }
return this._super(attrs); return this._super(attrs);
}, }
find(id) { static find(id) {
return ajax(`/admin/email/incoming/${id}.json`); return ajax(`/admin/email/incoming/${id}.json`);
}, }
findByBounced(id) { static findByBounced(id) {
return ajax(`/admin/email/incoming_from_bounced/${id}.json`); return ajax(`/admin/email/incoming_from_bounced/${id}.json`);
}, }
findAll(filter, offset) { static findAll(filter, offset) {
filter = filter || {}; filter = filter || {};
offset = offset || 0; offset = offset || 0;
@ -35,11 +33,9 @@ IncomingEmail.reopenClass({
}).then((incomings) => }).then((incomings) =>
incomings.map((incoming) => IncomingEmail.create(incoming)) incomings.map((incoming) => IncomingEmail.create(incoming))
); );
}, }
loadRawEmail(id) { static loadRawEmail(id) {
return ajax(`/admin/email/incoming/${id}/raw.json`); return ajax(`/admin/email/incoming/${id}/raw.json`);
}, }
}); }
export default IncomingEmail;

View File

@ -4,7 +4,15 @@ import EmberObject from "@ember/object";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
const Permalink = EmberObject.extend({ export default class Permalink extends EmberObject {
static findAll(filter) {
return ajax("/admin/permalinks.json", { data: { filter } }).then(function (
permalinks
) {
return permalinks.map((p) => Permalink.create(p));
});
}
save() { save() {
return ajax("/admin/permalinks.json", { return ajax("/admin/permalinks.json", {
type: "POST", type: "POST",
@ -14,33 +22,21 @@ const Permalink = EmberObject.extend({
permalink_type_value: this.permalink_type_value, permalink_type_value: this.permalink_type_value,
}, },
}); });
}, }
@discourseComputed("category_id") @discourseComputed("category_id")
category(category_id) { category(category_id) {
return Category.findById(category_id); return Category.findById(category_id);
}, }
@discourseComputed("external_url") @discourseComputed("external_url")
linkIsExternal(external_url) { linkIsExternal(external_url) {
return !DiscourseURL.isInternal(external_url); return !DiscourseURL.isInternal(external_url);
}, }
destroy() { destroy() {
return ajax("/admin/permalinks/" + this.id + ".json", { return ajax("/admin/permalinks/" + this.id + ".json", {
type: "DELETE", type: "DELETE",
}); });
}, }
}); }
Permalink.reopenClass({
findAll(filter) {
return ajax("/admin/permalinks.json", { data: { filter } }).then(function (
permalinks
) {
return permalinks.map((p) => Permalink.create(p));
});
},
});
export default Permalink;

View File

@ -19,12 +19,188 @@ import round from "discourse/lib/round";
// and you want to ensure cache is reset // and you want to ensure cache is reset
export const SCHEMA_VERSION = 4; export const SCHEMA_VERSION = 4;
const Report = EmberObject.extend({ export default class Report extends EmberObject {
average: false, static groupingForDatapoints(count) {
percent: false, if (count < DAILY_LIMIT_DAYS) {
higher_is_better: true, return "daily";
description_link: null, }
description: null,
if (count >= DAILY_LIMIT_DAYS && count < WEEKLY_LIMIT_DAYS) {
return "weekly";
}
if (count >= WEEKLY_LIMIT_DAYS) {
return "monthly";
}
}
static unitForDatapoints(count) {
if (count >= DAILY_LIMIT_DAYS && count < WEEKLY_LIMIT_DAYS) {
return "week";
} else if (count >= WEEKLY_LIMIT_DAYS) {
return "month";
} else {
return "day";
}
}
static unitForGrouping(grouping) {
switch (grouping) {
case "monthly":
return "month";
case "weekly":
return "week";
default:
return "day";
}
}
static collapse(model, data, grouping) {
grouping = grouping || Report.groupingForDatapoints(data.length);
if (grouping === "daily") {
return data;
} else if (grouping === "weekly" || grouping === "monthly") {
const isoKind = grouping === "weekly" ? "isoWeek" : "month";
const kind = grouping === "weekly" ? "week" : "month";
const startMoment = moment(model.start_date, "YYYY-MM-DD");
let currentIndex = 0;
let currentStart = startMoment.clone().startOf(isoKind);
let currentEnd = startMoment.clone().endOf(isoKind);
const transformedData = [
{
x: currentStart.format("YYYY-MM-DD"),
y: 0,
},
];
let appliedAverage = false;
data.forEach((d) => {
const date = moment(d.x, "YYYY-MM-DD");
if (
!date.isSame(currentStart) &&
!date.isBetween(currentStart, currentEnd)
) {
if (model.average) {
transformedData[currentIndex].y = applyAverage(
transformedData[currentIndex].y,
currentStart,
currentEnd
);
appliedAverage = true;
}
currentIndex += 1;
currentStart = currentStart.add(1, kind).startOf(isoKind);
currentEnd = currentEnd.add(1, kind).endOf(isoKind);
} else {
appliedAverage = false;
}
if (transformedData[currentIndex]) {
transformedData[currentIndex].y += d.y;
} else {
transformedData[currentIndex] = {
x: d.x,
y: d.y,
};
}
});
if (model.average && !appliedAverage) {
transformedData[currentIndex].y = applyAverage(
transformedData[currentIndex].y,
currentStart,
moment(model.end_date).subtract(1, "day") // remove 1 day as model end date is at 00:00 of next day
);
}
return transformedData;
}
// ensure we return something if grouping is unknown
return data;
}
static fillMissingDates(report, options = {}) {
const dataField = options.dataField || "data";
const filledField = options.filledField || "data";
const startDate = options.startDate || "start_date";
const endDate = options.endDate || "end_date";
if (Array.isArray(report[dataField])) {
const startDateFormatted = moment
.utc(report[startDate])
.locale("en")
.format("YYYY-MM-DD");
const endDateFormatted = moment
.utc(report[endDate])
.locale("en")
.format("YYYY-MM-DD");
if (report.modes[0] === "stacked_chart") {
report[filledField] = report[dataField].map((rep) => {
return {
req: rep.req,
label: rep.label,
color: rep.color,
data: fillMissingDates(
JSON.parse(JSON.stringify(rep.data)),
startDateFormatted,
endDateFormatted
),
};
});
} else {
report[filledField] = fillMissingDates(
JSON.parse(JSON.stringify(report[dataField])),
startDateFormatted,
endDateFormatted
);
}
}
}
static find(type, startDate, endDate, categoryId, groupId) {
return ajax("/admin/reports/" + type, {
data: {
start_date: startDate,
end_date: endDate,
category_id: categoryId,
group_id: groupId,
},
}).then((json) => {
// dont fill for large multi column tables
// which are not date based
const modes = json.report.modes;
if (modes.length !== 1 && modes[0] !== "table") {
Report.fillMissingDates(json.report);
}
const model = Report.create({ type });
model.setProperties(json.report);
if (json.report.related_report) {
// TODO: fillMissingDates if xaxis is date
const related = Report.create({
type: json.report.related_report.type,
});
related.setProperties(json.report.related_report);
model.set("relatedReport", related);
}
return model;
});
}
average = false;
percent = false;
higher_is_better = true;
description_link = null;
description = null;
@discourseComputed("type", "start_date", "end_date") @discourseComputed("type", "start_date", "end_date")
reportUrl(type, start_date, end_date) { reportUrl(type, start_date, end_date) {
@ -35,7 +211,7 @@ const Report = EmberObject.extend({
return getURL( return getURL(
`/admin/reports/${type}?start_date=${start_date}&end_date=${end_date}` `/admin/reports/${type}?start_date=${start_date}&end_date=${end_date}`
); );
}, }
valueAt(numDaysAgo) { valueAt(numDaysAgo) {
if (this.data) { if (this.data) {
@ -49,7 +225,7 @@ const Report = EmberObject.extend({
} }
} }
return 0; return 0;
}, }
valueFor(startDaysAgo, endDaysAgo) { valueFor(startDaysAgo, endDaysAgo) {
if (this.data) { if (this.data) {
@ -70,46 +246,46 @@ const Report = EmberObject.extend({
} }
return round(sum, -2); return round(sum, -2);
} }
}, }
@discourseComputed("data", "average") @discourseComputed("data", "average")
todayCount() { todayCount() {
return this.valueAt(0); return this.valueAt(0);
}, }
@discourseComputed("data", "average") @discourseComputed("data", "average")
yesterdayCount() { yesterdayCount() {
return this.valueAt(1); return this.valueAt(1);
}, }
@discourseComputed("data", "average") @discourseComputed("data", "average")
sevenDaysAgoCount() { sevenDaysAgoCount() {
return this.valueAt(7); return this.valueAt(7);
}, }
@discourseComputed("data", "average") @discourseComputed("data", "average")
thirtyDaysAgoCount() { thirtyDaysAgoCount() {
return this.valueAt(30); return this.valueAt(30);
}, }
@discourseComputed("data", "average") @discourseComputed("data", "average")
lastSevenDaysCount() { lastSevenDaysCount() {
return this.averageCount(7, this.valueFor(1, 7)); return this.averageCount(7, this.valueFor(1, 7));
}, }
@discourseComputed("data", "average") @discourseComputed("data", "average")
lastThirtyDaysCount() { lastThirtyDaysCount() {
return this.averageCount(30, this.valueFor(1, 30)); return this.averageCount(30, this.valueFor(1, 30));
}, }
averageCount(count, value) { averageCount(count, value) {
return this.average ? value / count : value; return this.average ? value / count : value;
}, }
@discourseComputed("yesterdayCount", "higher_is_better") @discourseComputed("yesterdayCount", "higher_is_better")
yesterdayTrend(yesterdayCount, higherIsBetter) { yesterdayTrend(yesterdayCount, higherIsBetter) {
return this._computeTrend(this.valueAt(2), yesterdayCount, higherIsBetter); return this._computeTrend(this.valueAt(2), yesterdayCount, higherIsBetter);
}, }
@discourseComputed("lastSevenDaysCount", "higher_is_better") @discourseComputed("lastSevenDaysCount", "higher_is_better")
sevenDaysTrend(lastSevenDaysCount, higherIsBetter) { sevenDaysTrend(lastSevenDaysCount, higherIsBetter) {
@ -118,39 +294,39 @@ const Report = EmberObject.extend({
lastSevenDaysCount, lastSevenDaysCount,
higherIsBetter higherIsBetter
); );
}, }
@discourseComputed("data") @discourseComputed("data")
currentTotal(data) { currentTotal(data) {
return data.reduce((cur, pair) => cur + pair.y, 0); return data.reduce((cur, pair) => cur + pair.y, 0);
}, }
@discourseComputed("data", "currentTotal") @discourseComputed("data", "currentTotal")
currentAverage(data, total) { currentAverage(data, total) {
return makeArray(data).length === 0 return makeArray(data).length === 0
? 0 ? 0
: parseFloat((total / parseFloat(data.length)).toFixed(1)); : parseFloat((total / parseFloat(data.length)).toFixed(1));
}, }
@discourseComputed("trend", "higher_is_better") @discourseComputed("trend", "higher_is_better")
trendIcon(trend, higherIsBetter) { trendIcon(trend, higherIsBetter) {
return this._iconForTrend(trend, higherIsBetter); return this._iconForTrend(trend, higherIsBetter);
}, }
@discourseComputed("sevenDaysTrend", "higher_is_better") @discourseComputed("sevenDaysTrend", "higher_is_better")
sevenDaysTrendIcon(sevenDaysTrend, higherIsBetter) { sevenDaysTrendIcon(sevenDaysTrend, higherIsBetter) {
return this._iconForTrend(sevenDaysTrend, higherIsBetter); return this._iconForTrend(sevenDaysTrend, higherIsBetter);
}, }
@discourseComputed("thirtyDaysTrend", "higher_is_better") @discourseComputed("thirtyDaysTrend", "higher_is_better")
thirtyDaysTrendIcon(thirtyDaysTrend, higherIsBetter) { thirtyDaysTrendIcon(thirtyDaysTrend, higherIsBetter) {
return this._iconForTrend(thirtyDaysTrend, higherIsBetter); return this._iconForTrend(thirtyDaysTrend, higherIsBetter);
}, }
@discourseComputed("yesterdayTrend", "higher_is_better") @discourseComputed("yesterdayTrend", "higher_is_better")
yesterdayTrendIcon(yesterdayTrend, higherIsBetter) { yesterdayTrendIcon(yesterdayTrend, higherIsBetter) {
return this._iconForTrend(yesterdayTrend, higherIsBetter); return this._iconForTrend(yesterdayTrend, higherIsBetter);
}, }
@discourseComputed( @discourseComputed(
"prev_period", "prev_period",
@ -161,7 +337,7 @@ const Report = EmberObject.extend({
trend(prev, currentTotal, currentAverage, higherIsBetter) { trend(prev, currentTotal, currentAverage, higherIsBetter) {
const total = this.average ? currentAverage : currentTotal; const total = this.average ? currentAverage : currentTotal;
return this._computeTrend(prev, total, higherIsBetter); return this._computeTrend(prev, total, higherIsBetter);
}, }
@discourseComputed( @discourseComputed(
"prev30Days", "prev30Days",
@ -180,7 +356,7 @@ const Report = EmberObject.extend({
lastThirtyDaysCount, lastThirtyDaysCount,
higherIsBetter higherIsBetter
); );
}, }
@discourseComputed("type") @discourseComputed("type")
method(type) { method(type) {
@ -189,7 +365,7 @@ const Report = EmberObject.extend({
} else { } else {
return "sum"; return "sum";
} }
}, }
percentChangeString(val1, val2) { percentChangeString(val1, val2) {
const change = this._computeChange(val1, val2); const change = this._computeChange(val1, val2);
@ -201,7 +377,7 @@ const Report = EmberObject.extend({
} else { } else {
return change.toFixed(0) + "%"; return change.toFixed(0) + "%";
} }
}, }
@discourseComputed("prev_period", "currentTotal", "currentAverage") @discourseComputed("prev_period", "currentTotal", "currentAverage")
trendTitle(prev, currentTotal, currentAverage) { trendTitle(prev, currentTotal, currentAverage) {
@ -224,7 +400,7 @@ const Report = EmberObject.extend({
prev, prev,
current, current,
}); });
}, }
changeTitle(valAtT1, valAtT2, prevPeriodString) { changeTitle(valAtT1, valAtT2, prevPeriodString) {
const change = this.percentChangeString(valAtT1, valAtT2); const change = this.percentChangeString(valAtT1, valAtT2);
@ -234,12 +410,12 @@ const Report = EmberObject.extend({
} }
title += `Was ${number(valAtT1)} ${prevPeriodString}.`; title += `Was ${number(valAtT1)} ${prevPeriodString}.`;
return title; return title;
}, }
@discourseComputed("yesterdayCount") @discourseComputed("yesterdayCount")
yesterdayCountTitle(yesterdayCount) { yesterdayCountTitle(yesterdayCount) {
return this.changeTitle(this.valueAt(2), yesterdayCount, "two days ago"); return this.changeTitle(this.valueAt(2), yesterdayCount, "two days ago");
}, }
@discourseComputed("lastSevenDaysCount") @discourseComputed("lastSevenDaysCount")
sevenDaysCountTitle(lastSevenDaysCount) { sevenDaysCountTitle(lastSevenDaysCount) {
@ -248,12 +424,12 @@ const Report = EmberObject.extend({
lastSevenDaysCount, lastSevenDaysCount,
"two weeks ago" "two weeks ago"
); );
}, }
@discourseComputed("prev30Days", "prev_period") @discourseComputed("prev30Days", "prev_period")
canDisplayTrendIcon(prev30Days, prev_period) { canDisplayTrendIcon(prev30Days, prev_period) {
return prev30Days ?? prev_period; return prev30Days ?? prev_period;
}, }
@discourseComputed("prev30Days", "prev_period", "lastThirtyDaysCount") @discourseComputed("prev30Days", "prev_period", "lastThirtyDaysCount")
thirtyDaysCountTitle(prev30Days, prev_period, lastThirtyDaysCount) { thirtyDaysCountTitle(prev30Days, prev_period, lastThirtyDaysCount) {
@ -262,12 +438,12 @@ const Report = EmberObject.extend({
lastThirtyDaysCount, lastThirtyDaysCount,
"in the previous 30 day period" "in the previous 30 day period"
); );
}, }
@discourseComputed("data") @discourseComputed("data")
sortedData(data) { sortedData(data) {
return this.xAxisIsDate ? data.toArray().reverse() : data.toArray(); return this.xAxisIsDate ? data.toArray().reverse() : data.toArray();
}, }
@discourseComputed("data") @discourseComputed("data")
xAxisIsDate() { xAxisIsDate() {
@ -275,7 +451,7 @@ const Report = EmberObject.extend({
return false; return false;
} }
return this.data && this.data[0].x.match(/\d{4}-\d{1,2}-\d{1,2}/); return this.data && this.data[0].x.match(/\d{4}-\d{1,2}-\d{1,2}/);
}, }
@discourseComputed("labels") @discourseComputed("labels")
computedLabels(labels) { computedLabels(labels) {
@ -359,7 +535,7 @@ const Report = EmberObject.extend({
}, },
}; };
}); });
}, }
_userLabel(properties, row) { _userLabel(properties, row) {
const username = row[properties.username]; const username = row[properties.username];
@ -388,7 +564,7 @@ const Report = EmberObject.extend({
value: username, value: username,
formattedValue: username ? formattedValue() : "—", formattedValue: username ? formattedValue() : "—",
}; };
}, }
_topicLabel(properties, row) { _topicLabel(properties, row) {
const topicTitle = row[properties.title]; const topicTitle = row[properties.title];
@ -403,7 +579,7 @@ const Report = EmberObject.extend({
value: topicTitle, value: topicTitle,
formattedValue: topicTitle ? formattedValue() : "—", formattedValue: topicTitle ? formattedValue() : "—",
}; };
}, }
_postLabel(properties, row) { _postLabel(properties, row) {
const postTitle = row[properties.truncated_raw]; const postTitle = row[properties.truncated_raw];
@ -419,21 +595,21 @@ const Report = EmberObject.extend({
? `<a href='${href}'>${escapeExpression(postTitle)}</a>` ? `<a href='${href}'>${escapeExpression(postTitle)}</a>`
: "—", : "—",
}; };
}, }
_secondsLabel(value) { _secondsLabel(value) {
return { return {
value: toNumber(value), value: toNumber(value),
formattedValue: durationTiny(value), formattedValue: durationTiny(value),
}; };
}, }
_percentLabel(value) { _percentLabel(value) {
return { return {
value: toNumber(value), value: toNumber(value),
formattedValue: value ? `${value}%` : "—", formattedValue: value ? `${value}%` : "—",
}; };
}, }
_numberLabel(value, options = {}) { _numberLabel(value, options = {}) {
const formatNumbers = isEmpty(options.formatNumbers) const formatNumbers = isEmpty(options.formatNumbers)
@ -446,21 +622,21 @@ const Report = EmberObject.extend({
value: toNumber(value), value: toNumber(value),
formattedValue: value ? formattedValue() : "—", formattedValue: value ? formattedValue() : "—",
}; };
}, }
_bytesLabel(value) { _bytesLabel(value) {
return { return {
value: toNumber(value), value: toNumber(value),
formattedValue: I18n.toHumanSize(value), formattedValue: I18n.toHumanSize(value),
}; };
}, }
_dateLabel(value, date, format = "LL") { _dateLabel(value, date, format = "LL") {
return { return {
value, value,
formattedValue: value ? date.format(format) : "—", formattedValue: value ? date.format(format) : "—",
}; };
}, }
_textLabel(value) { _textLabel(value) {
const escaped = escapeExpression(value); const escaped = escapeExpression(value);
@ -469,7 +645,7 @@ const Report = EmberObject.extend({
value, value,
formattedValue: value ? escaped : "—", formattedValue: value ? escaped : "—",
}; };
}, }
_linkLabel(properties, row) { _linkLabel(properties, row) {
const property = properties[0]; const property = properties[0];
@ -484,11 +660,11 @@ const Report = EmberObject.extend({
value, value,
formattedValue: value ? formattedValue(value, row[properties[1]]) : "—", formattedValue: value ? formattedValue(value, row[properties[1]]) : "—",
}; };
}, }
_computeChange(valAtT1, valAtT2) { _computeChange(valAtT1, valAtT2) {
return ((valAtT2 - valAtT1) / valAtT1) * 100; return ((valAtT2 - valAtT1) / valAtT1) * 100;
}, }
_computeTrend(valAtT1, valAtT2, higherIsBetter) { _computeTrend(valAtT1, valAtT2, higherIsBetter) {
const change = this._computeChange(valAtT1, valAtT2); const change = this._computeChange(valAtT1, valAtT2);
@ -504,7 +680,7 @@ const Report = EmberObject.extend({
} else if (change < -2) { } else if (change < -2) {
return higherIsBetter ? "trending-down" : "trending-up"; return higherIsBetter ? "trending-down" : "trending-up";
} }
}, }
_iconForTrend(trend, higherIsBetter) { _iconForTrend(trend, higherIsBetter) {
switch (trend) { switch (trend) {
@ -519,8 +695,8 @@ const Report = EmberObject.extend({
default: default:
return "minus"; return "minus";
} }
}, }
}); }
export const WEEKLY_LIMIT_DAYS = 365; export const WEEKLY_LIMIT_DAYS = 365;
export const DAILY_LIMIT_DAYS = 34; export const DAILY_LIMIT_DAYS = 34;
@ -529,183 +705,3 @@ function applyAverage(value, start, end) {
const count = end.diff(start, "day") + 1; // 1 to include start const count = end.diff(start, "day") + 1; // 1 to include start
return parseFloat((value / count).toFixed(2)); return parseFloat((value / count).toFixed(2));
} }
Report.reopenClass({
groupingForDatapoints(count) {
if (count < DAILY_LIMIT_DAYS) {
return "daily";
}
if (count >= DAILY_LIMIT_DAYS && count < WEEKLY_LIMIT_DAYS) {
return "weekly";
}
if (count >= WEEKLY_LIMIT_DAYS) {
return "monthly";
}
},
unitForDatapoints(count) {
if (count >= DAILY_LIMIT_DAYS && count < WEEKLY_LIMIT_DAYS) {
return "week";
} else if (count >= WEEKLY_LIMIT_DAYS) {
return "month";
} else {
return "day";
}
},
unitForGrouping(grouping) {
switch (grouping) {
case "monthly":
return "month";
case "weekly":
return "week";
default:
return "day";
}
},
collapse(model, data, grouping) {
grouping = grouping || Report.groupingForDatapoints(data.length);
if (grouping === "daily") {
return data;
} else if (grouping === "weekly" || grouping === "monthly") {
const isoKind = grouping === "weekly" ? "isoWeek" : "month";
const kind = grouping === "weekly" ? "week" : "month";
const startMoment = moment(model.start_date, "YYYY-MM-DD");
let currentIndex = 0;
let currentStart = startMoment.clone().startOf(isoKind);
let currentEnd = startMoment.clone().endOf(isoKind);
const transformedData = [
{
x: currentStart.format("YYYY-MM-DD"),
y: 0,
},
];
let appliedAverage = false;
data.forEach((d) => {
const date = moment(d.x, "YYYY-MM-DD");
if (
!date.isSame(currentStart) &&
!date.isBetween(currentStart, currentEnd)
) {
if (model.average) {
transformedData[currentIndex].y = applyAverage(
transformedData[currentIndex].y,
currentStart,
currentEnd
);
appliedAverage = true;
}
currentIndex += 1;
currentStart = currentStart.add(1, kind).startOf(isoKind);
currentEnd = currentEnd.add(1, kind).endOf(isoKind);
} else {
appliedAverage = false;
}
if (transformedData[currentIndex]) {
transformedData[currentIndex].y += d.y;
} else {
transformedData[currentIndex] = {
x: d.x,
y: d.y,
};
}
});
if (model.average && !appliedAverage) {
transformedData[currentIndex].y = applyAverage(
transformedData[currentIndex].y,
currentStart,
moment(model.end_date).subtract(1, "day") // remove 1 day as model end date is at 00:00 of next day
);
}
return transformedData;
}
// ensure we return something if grouping is unknown
return data;
},
fillMissingDates(report, options = {}) {
const dataField = options.dataField || "data";
const filledField = options.filledField || "data";
const startDate = options.startDate || "start_date";
const endDate = options.endDate || "end_date";
if (Array.isArray(report[dataField])) {
const startDateFormatted = moment
.utc(report[startDate])
.locale("en")
.format("YYYY-MM-DD");
const endDateFormatted = moment
.utc(report[endDate])
.locale("en")
.format("YYYY-MM-DD");
if (report.modes[0] === "stacked_chart") {
report[filledField] = report[dataField].map((rep) => {
return {
req: rep.req,
label: rep.label,
color: rep.color,
data: fillMissingDates(
JSON.parse(JSON.stringify(rep.data)),
startDateFormatted,
endDateFormatted
),
};
});
} else {
report[filledField] = fillMissingDates(
JSON.parse(JSON.stringify(report[dataField])),
startDateFormatted,
endDateFormatted
);
}
}
},
find(type, startDate, endDate, categoryId, groupId) {
return ajax("/admin/reports/" + type, {
data: {
start_date: startDate,
end_date: endDate,
category_id: categoryId,
group_id: groupId,
},
}).then((json) => {
// dont fill for large multi column tables
// which are not date based
const modes = json.report.modes;
if (modes.length !== 1 && modes[0] !== "table") {
Report.fillMissingDates(json.report);
}
const model = Report.create({ type });
model.setProperties(json.report);
if (json.report.related_report) {
// TODO: fillMissingDates if xaxis is date
const related = Report.create({
type: json.report.related_report.type,
});
related.setProperties(json.report.related_report);
model.set("relatedReport", related);
}
return model;
});
},
});
export default Report;

View File

@ -3,21 +3,8 @@ import I18n from "I18n";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
const ScreenedEmail = EmberObject.extend({ export default class ScreenedEmail extends EmberObject {
@discourseComputed("action") static findAll() {
actionName(action) {
return I18n.t("admin.logs.screened_actions." + action);
},
clearBlock() {
return ajax("/admin/logs/screened_emails/" + this.id, {
type: "DELETE",
});
},
});
ScreenedEmail.reopenClass({
findAll() {
return ajax("/admin/logs/screened_emails.json").then(function ( return ajax("/admin/logs/screened_emails.json").then(function (
screened_emails screened_emails
) { ) {
@ -25,7 +12,16 @@ ScreenedEmail.reopenClass({
return ScreenedEmail.create(b); return ScreenedEmail.create(b);
}); });
}); });
}, }
});
export default ScreenedEmail; @discourseComputed("action")
actionName(action) {
return I18n.t("admin.logs.screened_actions." + action);
}
clearBlock() {
return ajax("/admin/logs/screened_emails/" + this.id, {
type: "DELETE",
});
}
}

View File

@ -1,21 +1,28 @@
import { equal } from "@ember/object/computed";
import EmberObject from "@ember/object"; import EmberObject from "@ember/object";
import I18n from "I18n"; import I18n from "I18n";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import { equal } from "@ember/object/computed";
const ScreenedIpAddress = EmberObject.extend({ export default class ScreenedIpAddress extends EmberObject {
static findAll(filter) {
return ajax("/admin/logs/screened_ip_addresses.json", {
data: { filter },
}).then((screened_ips) =>
screened_ips.map((b) => ScreenedIpAddress.create(b))
);
}
@equal("action_name", "block") isBlocked;
@discourseComputed("action_name") @discourseComputed("action_name")
actionName(actionName) { actionName(actionName) {
return I18n.t(`admin.logs.screened_ips.actions.${actionName}`); return I18n.t(`admin.logs.screened_ips.actions.${actionName}`);
}, }
isBlocked: equal("action_name", "block"),
@discourseComputed("ip_address") @discourseComputed("ip_address")
isRange(ipAddress) { isRange(ipAddress) {
return ipAddress.indexOf("/") > 0; return ipAddress.indexOf("/") > 0;
}, }
save() { save() {
return ajax( return ajax(
@ -30,23 +37,11 @@ const ScreenedIpAddress = EmberObject.extend({
}, },
} }
); );
}, }
destroy() { destroy() {
return ajax("/admin/logs/screened_ip_addresses/" + this.id + ".json", { return ajax("/admin/logs/screened_ip_addresses/" + this.id + ".json", {
type: "DELETE", type: "DELETE",
}); });
}, }
}); }
ScreenedIpAddress.reopenClass({
findAll(filter) {
return ajax("/admin/logs/screened_ip_addresses.json", {
data: { filter },
}).then((screened_ips) =>
screened_ips.map((b) => ScreenedIpAddress.create(b))
);
},
});
export default ScreenedIpAddress;

View File

@ -3,15 +3,8 @@ import I18n from "I18n";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
const ScreenedUrl = EmberObject.extend({ export default class ScreenedUrl extends EmberObject {
@discourseComputed("action") static findAll() {
actionName(action) {
return I18n.t("admin.logs.screened_actions." + action);
},
});
ScreenedUrl.reopenClass({
findAll() {
return ajax("/admin/logs/screened_urls.json").then(function ( return ajax("/admin/logs/screened_urls.json").then(function (
screened_urls screened_urls
) { ) {
@ -19,7 +12,10 @@ ScreenedUrl.reopenClass({
return ScreenedUrl.create(b); return ScreenedUrl.create(b);
}); });
}); });
}, }
});
export default ScreenedUrl; @discourseComputed("action")
actionName(action) {
return I18n.t("admin.logs.screened_actions." + action);
}
}

View File

@ -4,22 +4,8 @@ import Setting from "admin/mixins/setting-object";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
const SiteSetting = EmberObject.extend(Setting, { export default class SiteSetting extends EmberObject.extend(Setting) {
@discourseComputed("setting") static findAll() {
staffLogFilter(setting) {
if (!setting) {
return;
}
return {
subject: setting,
action_name: "change_site_setting",
};
},
});
SiteSetting.reopenClass({
findAll() {
return ajax("/admin/site_settings").then(function (settings) { return ajax("/admin/site_settings").then(function (settings) {
// Group the results by category // Group the results by category
const categories = {}; const categories = {};
@ -38,9 +24,9 @@ SiteSetting.reopenClass({
}; };
}); });
}); });
}, }
update(key, value, opts = {}) { static update(key, value, opts = {}) {
const data = {}; const data = {};
data[key] = value; data[key] = value;
@ -49,7 +35,17 @@ SiteSetting.reopenClass({
} }
return ajax(`/admin/site_settings/${key}`, { type: "PUT", data }); return ajax(`/admin/site_settings/${key}`, { type: "PUT", data });
}, }
});
export default SiteSetting; @discourseComputed("setting")
staffLogFilter(setting) {
if (!setting) {
return;
}
return {
subject: setting,
action_name: "change_site_setting",
};
}
}

View File

@ -2,10 +2,10 @@ import RestModel from "discourse/models/rest";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { getProperties } from "@ember/object"; import { getProperties } from "@ember/object";
export default RestModel.extend({ export default class SiteText extends RestModel {
revert(locale) { revert(locale) {
return ajax(`/admin/customize/site_texts/${this.id}?locale=${locale}`, { return ajax(`/admin/customize/site_texts/${this.id}?locale=${locale}`, {
type: "DELETE", type: "DELETE",
}).then((result) => getProperties(result.site_text, "value", "can_revert")); }).then((result) => getProperties(result.site_text, "value", "can_revert"));
}, }
}); }

View File

@ -11,13 +11,36 @@ function format(label, value, escape = true) {
: ""; : "";
} }
const StaffActionLog = RestModel.extend({ export default class StaffActionLog extends RestModel {
showFullDetails: false, static munge(json) {
if (json.acting_user) {
json.acting_user = AdminUser.create(json.acting_user);
}
if (json.target_user) {
json.target_user = AdminUser.create(json.target_user);
}
return json;
}
static findAll(data) {
return ajax("/admin/logs/staff_action_logs.json", { data }).then(
(result) => {
return {
staff_action_logs: result.staff_action_logs.map((s) =>
StaffActionLog.create(s)
),
user_history_actions: result.user_history_actions,
};
}
);
}
showFullDetails = false;
@discourseComputed("action_name") @discourseComputed("action_name")
actionName(actionName) { actionName(actionName) {
return I18n.t(`admin.logs.staff_actions.actions.${actionName}`); return I18n.t(`admin.logs.staff_actions.actions.${actionName}`);
}, }
@discourseComputed( @discourseComputed(
"email", "email",
@ -72,42 +95,15 @@ const StaffActionLog = RestModel.extend({
const formatted = lines.filter((l) => l.length > 0).join("<br/>"); const formatted = lines.filter((l) => l.length > 0).join("<br/>");
return formatted.length > 0 ? formatted + "<br/>" : ""; return formatted.length > 0 ? formatted + "<br/>" : "";
}, }
@discourseComputed("details") @discourseComputed("details")
useModalForDetails(details) { useModalForDetails(details) {
return details && details.length > 100; return details && details.length > 100;
}, }
@discourseComputed("action_name") @discourseComputed("action_name")
useCustomModalForDetails(actionName) { useCustomModalForDetails(actionName) {
return ["change_theme", "delete_theme"].includes(actionName); return ["change_theme", "delete_theme"].includes(actionName);
},
});
StaffActionLog.reopenClass({
munge(json) {
if (json.acting_user) {
json.acting_user = AdminUser.create(json.acting_user);
} }
if (json.target_user) { }
json.target_user = AdminUser.create(json.target_user);
}
return json;
},
findAll(data) {
return ajax("/admin/logs/staff_action_logs.json", { data }).then(
(result) => {
return {
staff_action_logs: result.staff_action_logs.map((s) =>
StaffActionLog.create(s)
),
user_history_actions: result.user_history_actions,
};
}
);
},
});
export default StaffActionLog;

View File

@ -1,4 +1,4 @@
import EmberObject from "@ember/object"; import EmberObject from "@ember/object";
import Setting from "admin/mixins/setting-object"; import Setting from "admin/mixins/setting-object";
export default EmberObject.extend(Setting, {}); export default class ThemeSettings extends EmberObject.extend(Setting) {}

View File

@ -13,11 +13,13 @@ export const THEMES = "themes";
export const COMPONENTS = "components"; export const COMPONENTS = "components";
const SETTINGS_TYPE_ID = 5; const SETTINGS_TYPE_ID = 5;
const Theme = RestModel.extend({ class Theme extends RestModel {
isActive: or("default", "user_selectable"), @or("default", "user_selectable") isActive;
isPendingUpdates: gt("remote_theme.commits_behind", 0), @gt("remote_theme.commits_behind", 0) isPendingUpdates;
hasEditedFields: gt("editedFields.length", 0), @gt("editedFields.length", 0) hasEditedFields;
hasParents: gt("parent_themes.length", 0), @gt("parent_themes.length", 0) hasParents;
changed = false;
@discourseComputed("theme_fields.[]") @discourseComputed("theme_fields.[]")
targets() { targets() {
@ -45,7 +47,7 @@ const Theme = RestModel.extend({
target["error"] = this.hasError(target.name); target["error"] = this.hasError(target.name);
return target; return target;
}); });
}, }
@discourseComputed("theme_fields.[]") @discourseComputed("theme_fields.[]")
fieldNames() { fieldNames() {
@ -84,7 +86,7 @@ const Theme = RestModel.extend({
], ],
extra_scss: scss_fields, extra_scss: scss_fields,
}; };
}, }
@discourseComputed( @discourseComputed(
"fieldNames", "fieldNames",
@ -118,7 +120,7 @@ const Theme = RestModel.extend({
}); });
}); });
return hash; return hash;
}, }
@discourseComputed("theme_fields") @discourseComputed("theme_fields")
themeFields(fields) { themeFields(fields) {
@ -134,7 +136,7 @@ const Theme = RestModel.extend({
} }
}); });
return hash; return hash;
}, }
@discourseComputed("theme_fields", "theme_fields.[]") @discourseComputed("theme_fields", "theme_fields.[]")
uploads(fields) { uploads(fields) {
@ -144,32 +146,32 @@ const Theme = RestModel.extend({
return fields.filter( return fields.filter(
(f) => f.target === "common" && f.type_id === THEME_UPLOAD_VAR (f) => f.target === "common" && f.type_id === THEME_UPLOAD_VAR
); );
}, }
@discourseComputed("theme_fields", "theme_fields.@each.error") @discourseComputed("theme_fields", "theme_fields.@each.error")
isBroken(fields) { isBroken(fields) {
return ( return (
fields && fields.any((field) => field.error && field.error.length > 0) fields && fields.any((field) => field.error && field.error.length > 0)
); );
}, }
@discourseComputed("theme_fields.[]") @discourseComputed("theme_fields.[]")
editedFields(fields) { editedFields(fields) {
return fields.filter( return fields.filter(
(field) => !isBlank(field.value) && field.type_id !== SETTINGS_TYPE_ID (field) => !isBlank(field.value) && field.type_id !== SETTINGS_TYPE_ID
); );
}, }
@discourseComputed("remote_theme.last_error_text") @discourseComputed("remote_theme.last_error_text")
remoteError(errorText) { remoteError(errorText) {
if (errorText && errorText.length > 0) { if (errorText && errorText.length > 0) {
return errorText; return errorText;
} }
}, }
getKey(field) { getKey(field) {
return `${field.target} ${field.name}`; return `${field.target} ${field.name}`;
}, }
hasEdited(target, name) { hasEdited(target, name) {
if (name) { if (name) {
@ -180,27 +182,27 @@ const Theme = RestModel.extend({
(field) => field.target === target && !isEmpty(field.value) (field) => field.target === target && !isEmpty(field.value)
); );
} }
}, }
hasError(target, name) { hasError(target, name) {
return this.theme_fields return this.theme_fields
.filter((f) => f.target === target && (!name || name === f.name)) .filter((f) => f.target === target && (!name || name === f.name))
.any((f) => f.error); .any((f) => f.error);
}, }
getError(target, name) { getError(target, name) {
let themeFields = this.themeFields; let themeFields = this.themeFields;
let key = this.getKey({ target, name }); let key = this.getKey({ target, name });
let field = themeFields[key]; let field = themeFields[key];
return field ? field.error : ""; return field ? field.error : "";
}, }
getField(target, name) { getField(target, name) {
let themeFields = this.themeFields; let themeFields = this.themeFields;
let key = this.getKey({ target, name }); let key = this.getKey({ target, name });
let field = themeFields[key]; let field = themeFields[key];
return field ? field.value : ""; return field ? field.value : "";
}, }
removeField(field) { removeField(field) {
this.set("changed", true); this.set("changed", true);
@ -209,7 +211,7 @@ const Theme = RestModel.extend({
field.value = null; field.value = null;
return this.saveChanges("theme_fields"); return this.saveChanges("theme_fields");
}, }
setField(target, name, value, upload_id, type_id) { setField(target, name, value, upload_id, type_id) {
this.set("changed", true); this.set("changed", true);
@ -249,25 +251,25 @@ const Theme = RestModel.extend({
this.notifyPropertyChange("theme_fields.[]"); this.notifyPropertyChange("theme_fields.[]");
} }
} }
}, }
@discourseComputed("childThemes.[]") @discourseComputed("childThemes.[]")
child_theme_ids(childThemes) { child_theme_ids(childThemes) {
if (childThemes) { if (childThemes) {
return childThemes.map((theme) => get(theme, "id")); return childThemes.map((theme) => get(theme, "id"));
} }
}, }
@discourseComputed("recentlyInstalled", "component", "hasParents") @discourseComputed("recentlyInstalled", "component", "hasParents")
warnUnassignedComponent(recent, component, hasParents) { warnUnassignedComponent(recent, component, hasParents) {
return recent && component && !hasParents; return recent && component && !hasParents;
}, }
removeChildTheme(theme) { removeChildTheme(theme) {
const childThemes = this.childThemes; const childThemes = this.childThemes;
childThemes.removeObject(theme); childThemes.removeObject(theme);
return this.saveChanges("child_theme_ids"); return this.saveChanges("child_theme_ids");
}, }
addChildTheme(theme) { addChildTheme(theme) {
let childThemes = this.childThemes; let childThemes = this.childThemes;
@ -278,7 +280,7 @@ const Theme = RestModel.extend({
childThemes.removeObject(theme); childThemes.removeObject(theme);
childThemes.pushObject(theme); childThemes.pushObject(theme);
return this.saveChanges("child_theme_ids"); return this.saveChanges("child_theme_ids");
}, }
addParentTheme(theme) { addParentTheme(theme) {
let parentThemes = this.parentThemes; let parentThemes = this.parentThemes;
@ -287,38 +289,36 @@ const Theme = RestModel.extend({
this.set("parentThemes", parentThemes); this.set("parentThemes", parentThemes);
} }
parentThemes.addObject(theme); parentThemes.addObject(theme);
}, }
checkForUpdates() { checkForUpdates() {
return this.save({ remote_check: true }).then(() => return this.save({ remote_check: true }).then(() =>
this.set("changed", false) this.set("changed", false)
); );
}, }
updateToLatest() { updateToLatest() {
return this.save({ remote_update: true }).then(() => return this.save({ remote_update: true }).then(() =>
this.set("changed", false) this.set("changed", false)
); );
}, }
changed: false,
saveChanges() { saveChanges() {
const hash = this.getProperties.apply(this, arguments); const hash = this.getProperties.apply(this, arguments);
return this.save(hash) return this.save(hash)
.finally(() => this.set("changed", false)) .finally(() => this.set("changed", false))
.catch(popupAjaxError); .catch(popupAjaxError);
}, }
saveSettings(name, value) { saveSettings(name, value) {
const settings = {}; const settings = {};
settings[name] = value; settings[name] = value;
return this.save({ settings }); return this.save({ settings });
}, }
saveTranslation(name, value) { saveTranslation(name, value) {
return this.save({ translations: { [name]: value } }); return this.save({ translations: { [name]: value } });
}, }
}); }
export default Theme; export default Theme;

View File

@ -1,21 +1,21 @@
import EmberObject from "@ember/object"; import EmberObject from "@ember/object";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
export default EmberObject.extend({ export default class Tl3Requirements extends EmberObject {
@discourseComputed("days_visited", "time_period") @discourseComputed("days_visited", "time_period")
days_visited_percent(daysVisited, timePeriod) { days_visited_percent(daysVisited, timePeriod) {
return Math.round((daysVisited * 100) / timePeriod); return Math.round((daysVisited * 100) / timePeriod);
}, }
@discourseComputed("min_days_visited", "time_period") @discourseComputed("min_days_visited", "time_period")
min_days_visited_percent(minDaysVisited, timePeriod) { min_days_visited_percent(minDaysVisited, timePeriod) {
return Math.round((minDaysVisited * 100) / timePeriod); return Math.round((minDaysVisited * 100) / timePeriod);
}, }
@discourseComputed("num_topics_replied_to", "min_topics_replied_to") @discourseComputed("num_topics_replied_to", "min_topics_replied_to")
capped_topics_replied_to(numReplied, minReplied) { capped_topics_replied_to(numReplied, minReplied) {
return numReplied > minReplied; return numReplied > minReplied;
}, }
@discourseComputed( @discourseComputed(
"days_visited", "days_visited",
@ -71,5 +71,5 @@ export default EmberObject.extend({
silenced: this.get("penalty_counts.silenced") === 0, silenced: this.get("penalty_counts.silenced") === 0,
suspended: this.get("penalty_counts.suspended") === 0, suspended: this.get("penalty_counts.suspended") === 0,
}; };
}, }
}); }

View File

@ -2,14 +2,8 @@ import EmberObject from "@ember/object";
import RestModel from "discourse/models/rest"; import RestModel from "discourse/models/rest";
import { i18n } from "discourse/lib/computed"; import { i18n } from "discourse/lib/computed";
const UserField = RestModel.extend(); export default class UserField extends RestModel {
static fieldTypes() {
const UserFieldType = EmberObject.extend({
name: i18n("id", "admin.user_fields.field_types.%@"),
});
UserField.reopenClass({
fieldTypes() {
if (!this._fieldTypes) { if (!this._fieldTypes) {
this._fieldTypes = [ this._fieldTypes = [
UserFieldType.create({ id: "text" }), UserFieldType.create({ id: "text" }),
@ -20,11 +14,13 @@ UserField.reopenClass({
} }
return this._fieldTypes; return this._fieldTypes;
}, }
fieldTypeById(id) { static fieldTypeById(id) {
return this.fieldTypes().findBy("id", id); return this.fieldTypes().findBy("id", id);
}, }
}); }
export default UserField; class UserFieldType extends EmberObject {
@i18n("id", "admin.user_fields.field_types.%@") name;
}

View File

@ -2,43 +2,39 @@ import EmberObject from "@ember/object";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
const VersionCheck = EmberObject.extend({ export default class VersionCheck extends EmberObject {
static find() {
return ajax("/admin/version_check").then((json) =>
VersionCheck.create(json)
);
}
@discourseComputed("updated_at") @discourseComputed("updated_at")
noCheckPerformed(updatedAt) { noCheckPerformed(updatedAt) {
return updatedAt === null; return updatedAt === null;
}, }
@discourseComputed("missing_versions_count") @discourseComputed("missing_versions_count")
upToDate(missingVersionsCount) { upToDate(missingVersionsCount) {
return missingVersionsCount === 0 || missingVersionsCount === null; return missingVersionsCount === 0 || missingVersionsCount === null;
}, }
@discourseComputed("missing_versions_count") @discourseComputed("missing_versions_count")
behindByOneVersion(missingVersionsCount) { behindByOneVersion(missingVersionsCount) {
return missingVersionsCount === 1; return missingVersionsCount === 1;
}, }
@discourseComputed("installed_sha") @discourseComputed("installed_sha")
gitLink(installedSHA) { gitLink(installedSHA) {
if (installedSHA) { if (installedSHA) {
return `https://github.com/discourse/discourse/commits/${installedSHA}`; return `https://github.com/discourse/discourse/commits/${installedSHA}`;
} }
}, }
@discourseComputed("installed_sha") @discourseComputed("installed_sha")
shortSha(installedSHA) { shortSha(installedSHA) {
if (installedSHA) { if (installedSHA) {
return installedSHA.slice(0, 10); return installedSHA.slice(0, 10);
} }
}, }
}); }
VersionCheck.reopenClass({
find() {
return ajax("/admin/version_check").then((json) =>
VersionCheck.create(json)
);
},
});
export default VersionCheck;

View File

@ -2,34 +2,8 @@ import EmberObject from "@ember/object";
import I18n from "I18n"; import I18n from "I18n";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
const WatchedWord = EmberObject.extend({ export default class WatchedWord extends EmberObject {
save() { static findAll() {
return ajax(
"/admin/customize/watched_words" +
(this.id ? "/" + this.id : "") +
".json",
{
type: this.id ? "PUT" : "POST",
data: {
word: this.word,
replacement: this.replacement,
action_key: this.action,
case_sensitive: this.isCaseSensitive,
},
dataType: "json",
}
);
},
destroy() {
return ajax("/admin/customize/watched_words/" + this.id + ".json", {
type: "DELETE",
});
},
});
WatchedWord.reopenClass({
findAll() {
return ajax("/admin/customize/watched_words.json").then((list) => { return ajax("/admin/customize/watched_words.json").then((list) => {
const actions = {}; const actions = {};
@ -50,7 +24,29 @@ WatchedWord.reopenClass({
}); });
}); });
}); });
}, }
});
export default WatchedWord; save() {
return ajax(
"/admin/customize/watched_words" +
(this.id ? "/" + this.id : "") +
".json",
{
type: this.id ? "PUT" : "POST",
data: {
word: this.word,
replacement: this.replacement,
action_key: this.action,
case_sensitive: this.isCaseSensitive,
},
dataType: "json",
}
);
}
destroy() {
return ajax("/admin/customize/watched_words/" + this.id + ".json", {
type: "DELETE",
});
}
}

View File

@ -1,33 +1,34 @@
import discourseComputed, { observes } from "discourse-common/utils/decorators"; import { computed } from "@ember/object";
import discourseComputed from "discourse-common/utils/decorators";
import { observes } from "@ember-decorators/object";
import Category from "discourse/models/category"; import Category from "discourse/models/category";
import Group from "discourse/models/group"; import Group from "discourse/models/group";
import RestModel from "discourse/models/rest"; import RestModel from "discourse/models/rest";
import Site from "discourse/models/site"; import Site from "discourse/models/site";
import { isEmpty } from "@ember/utils"; import { isEmpty } from "@ember/utils";
export default RestModel.extend({ export default class WebHook extends RestModel {
content_type: 1, // json content_type = 1; // json
last_delivery_status: 1, // inactive last_delivery_status = 1; // inactive
wildcard_web_hook: false, wildcard_web_hook = false;
verify_certificate: true, verify_certificate = true;
active: false, active = false;
web_hook_event_types: null, web_hook_event_types = null;
groupsFilterInName: null, groupsFilterInName = null;
@discourseComputed("wildcard_web_hook") @computed("wildcard_web_hook")
webhookType: { get wildcard() {
get(wildcard) { return this.wildcard_web_hook ? "wildcard" : "individual";
return wildcard ? "wildcard" : "individual"; }
},
set(value) { set wildcard(value) {
this.set("wildcard_web_hook", value === "wildcard"); this.set("wildcard_web_hook", value === "wildcard");
}, }
},
@discourseComputed("category_ids") @discourseComputed("category_ids")
categories(categoryIds) { categories(categoryIds) {
return Category.findByIds(categoryIds); return Category.findByIds(categoryIds);
}, }
@observes("group_ids") @observes("group_ids")
updateGroupsFilter() { updateGroupsFilter() {
@ -41,11 +42,11 @@ export default RestModel.extend({
return groupNames; return groupNames;
}, []) }, [])
); );
}, }
groupFinder(term) { groupFinder(term) {
return Group.findAll({ term, ignore_automatic: false }); return Group.findAll({ term, ignore_automatic: false });
}, }
@discourseComputed("wildcard_web_hook", "web_hook_event_types.[]") @discourseComputed("wildcard_web_hook", "web_hook_event_types.[]")
description(isWildcardWebHook, types) { description(isWildcardWebHook, types) {
@ -57,7 +58,7 @@ export default RestModel.extend({
}); });
return isWildcardWebHook ? "*" : desc; return isWildcardWebHook ? "*" : desc;
}, }
createProperties() { createProperties() {
const types = this.web_hook_event_types; const types = this.web_hook_event_types;
@ -92,9 +93,9 @@ export default RestModel.extend({
return groupIds; return groupIds;
}, []), }, []),
}; };
}, }
updateProperties() { updateProperties() {
return this.createProperties(); return this.createProperties();
}, }
}); }