From 64557c407611783506db7172be81ed5d63aa2172 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Fri, 17 Mar 2023 10:18:42 +0000 Subject: [PATCH] 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 --- .../admin/addon/models/admin-dashboard.js | 20 +- .../admin/addon/models/admin-user.js | 134 +++-- .../javascripts/admin/addon/models/api-key.js | 48 +- .../admin/addon/models/backup-status.js | 10 +- .../javascripts/admin/addon/models/backup.js | 44 +- .../admin/addon/models/color-scheme-color.js | 37 +- .../admin/addon/models/color-scheme.js | 95 ++-- .../admin/addon/models/email-log.js | 18 +- .../admin/addon/models/email-preview.js | 22 +- .../admin/addon/models/email-settings.js | 12 +- .../admin/addon/models/email-style.js | 8 +- .../admin/addon/models/email-template.js | 6 +- .../admin/addon/models/flag-type.js | 6 +- .../admin/addon/models/form-template.js | 34 +- .../admin/addon/models/incoming-email.js | 28 +- .../admin/addon/models/permalink.js | 32 +- .../javascripts/admin/addon/models/report.js | 458 +++++++++--------- .../admin/addon/models/screened-email.js | 32 +- .../admin/addon/models/screened-ip-address.js | 37 +- .../admin/addon/models/screened-url.js | 20 +- .../admin/addon/models/site-setting.js | 38 +- .../admin/addon/models/site-text.js | 6 +- .../admin/addon/models/staff-action-log.js | 64 ++- .../admin/addon/models/theme-settings.js | 2 +- .../javascripts/admin/addon/models/theme.js | 66 +-- .../admin/addon/models/tl3-requirements.js | 12 +- .../admin/addon/models/user-field.js | 22 +- .../admin/addon/models/version-check.js | 30 +- .../admin/addon/models/watched-word.js | 58 ++- .../admin/addon/models/web-hook.js | 51 +- 30 files changed, 684 insertions(+), 766 deletions(-) diff --git a/app/assets/javascripts/admin/addon/models/admin-dashboard.js b/app/assets/javascripts/admin/addon/models/admin-dashboard.js index c0c9f86702c..c261a424411 100644 --- a/app/assets/javascripts/admin/addon/models/admin-dashboard.js +++ b/app/assets/javascripts/admin/addon/models/admin-dashboard.js @@ -7,19 +7,17 @@ const GENERAL_ATTRIBUTES = [ "release_notes_link", ]; -const AdminDashboard = EmberObject.extend({}); - -AdminDashboard.reopenClass({ - fetch() { +export default class AdminDashboard extends EmberObject { + static fetch() { return ajax("/admin/dashboard.json").then((json) => { const model = AdminDashboard.create(); model.set("version_check", json.version_check); return model; }); - }, + } - fetchGeneral() { + static fetchGeneral() { return ajax("/admin/dashboard/general.json").then((json) => { const model = AdminDashboard.create(); @@ -34,15 +32,13 @@ AdminDashboard.reopenClass({ return model; }); - }, + } - fetchProblems() { + static fetchProblems() { return ajax("/admin/dashboard/problems.json").then((json) => { const model = AdminDashboard.create(json); model.set("loaded", true); return model; }); - }, -}); - -export default AdminDashboard; + } +} diff --git a/app/assets/javascripts/admin/addon/models/admin-user.js b/app/assets/javascripts/admin/addon/models/admin-user.js index a61980bc61a..8621fbfd494 100644 --- a/app/assets/javascripts/admin/addon/models/admin-user.js +++ b/app/assets/javascripts/admin/addon/models/admin-user.js @@ -10,14 +10,30 @@ import { popupAjaxError } from "discourse/lib/ajax-error"; import { propertyNotEqual } from "discourse/lib/computed"; 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({ - adminUserView: true, - customGroups: filter("groups", (g) => !g.automatic && Group.create(g)), - automaticGroups: filter("groups", (g) => g.automatic && Group.create(g)), + static findAll(query, userFilter) { + return ajax(`/admin/users/list/${query}.json`, { + data: userFilter, + }).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") bounceScore(bounce_score, reset_bounce_score_after) { @@ -28,7 +44,7 @@ const AdminUser = User.extend({ } else { return bounce_score; } - }, + } @discourseComputed("bounce_score") bounceScoreExplanation(bounce_score) { @@ -39,14 +55,12 @@ const AdminUser = User.extend({ } else { return I18n.t("admin.user.bounce_score_explanation.threshold_reached"); } - }, + } @discourseComputed bounceLink() { return getURL("/admin/email/bounced"); - }, - - canResetBounceScore: gt("bounce_score", 0), + } resetBounceScore() { return ajax(`/admin/users/${this.id}/reset_bounce_score`, { @@ -57,14 +71,14 @@ const AdminUser = User.extend({ reset_bounce_score_after: null, }) ); - }, + } groupAdded(added) { return ajax(`/admin/users/${this.id}/groups`, { type: "POST", data: { group_id: added.id }, }).then(() => this.groups.pushObject(added)); - }, + } groupRemoved(groupId) { return ajax(`/admin/users/${this.id}/groups/${groupId}`, { @@ -75,13 +89,13 @@ const AdminUser = User.extend({ this.set("primary_group_id", null); } }); - }, + } deleteAllPosts() { return ajax(`/admin/users/${this.get("id")}/delete_posts_batch`, { type: "PUT", }); - }, + } revokeAdmin() { 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, }); }); - }, + } grantAdmin(data) { return ajax(`/admin/users/${this.id}/grant_admin`, { @@ -114,7 +128,7 @@ const AdminUser = User.extend({ return resp; }); - }, + } revokeModeration() { return ajax(`/admin/users/${this.id}/revoke_moderation`, { @@ -130,7 +144,7 @@ const AdminUser = User.extend({ }); }) .catch(popupAjaxError); - }, + } grantModeration() { return ajax(`/admin/users/${this.id}/grant_moderation`, { @@ -146,7 +160,7 @@ const AdminUser = User.extend({ }); }) .catch(popupAjaxError); - }, + } disableSecondFactor() { return ajax(`/admin/users/${this.id}/disable_second_factor`, { @@ -156,7 +170,7 @@ const AdminUser = User.extend({ this.set("second_factor_enabled", false); }) .catch(popupAjaxError); - }, + } approve(approvedBy) { return ajax(`/admin/users/${this.id}/approve`, { @@ -168,83 +182,76 @@ const AdminUser = User.extend({ approved_by: approvedBy, }); }); - }, + } setOriginalTrustLevel() { this.set("originalTrustLevel", this.trust_level); - }, - - dirty: propertyNotEqual("originalTrustLevel", "trust_level"), + } saveTrustLevel() { return ajax(`/admin/users/${this.id}/trust_level`, { type: "PUT", data: { level: this.trust_level }, }); - }, + } restoreTrustLevel() { this.set("trust_level", this.originalTrustLevel); - }, + } lockTrustLevel(locked) { return ajax(`/admin/users/${this.id}/trust_level_lock`, { type: "PUT", data: { locked: !!locked }, }); - }, - - canLockTrustLevel: lt("trust_level", 4), - - canSuspend: not("staff"), - canSilence: not("staff"), + } @discourseComputed("suspended_till", "suspended_at") suspendDuration(suspendedTill, suspendedAt) { suspendedAt = moment(suspendedAt); suspendedTill = moment(suspendedTill); return suspendedAt.format("L") + " - " + suspendedTill.format("L"); - }, + } suspend(data) { return ajax(`/admin/users/${this.id}/suspend`, { type: "PUT", data, }).then((result) => this.setProperties(result.suspension)); - }, + } unsuspend() { return ajax(`/admin/users/${this.id}/unsuspend`, { type: "PUT", }).then((result) => this.setProperties(result.suspension)); - }, + } logOut() { return ajax("/admin/users/" + this.id + "/log_out", { type: "POST", data: { username_or_email: this.username }, }); - }, + } impersonate() { return ajax("/admin/impersonate", { type: "POST", data: { username_or_email: this.username }, }); - }, + } activate() { return ajax(`/admin/users/${this.id}/activate`, { type: "PUT", }); - }, + } deactivate() { return ajax(`/admin/users/${this.id}/deactivate`, { type: "PUT", data: { context: document.location.pathname }, }); - }, + } unsilence() { this.set("silencingUser", true); @@ -254,7 +261,7 @@ const AdminUser = User.extend({ }) .then((result) => this.setProperties(result.unsilence)) .finally(() => this.set("silencingUser", false)); - }, + } silence(data) { this.set("silencingUser", true); @@ -265,20 +272,20 @@ const AdminUser = User.extend({ }) .then((result) => this.setProperties(result.silence)) .finally(() => this.set("silencingUser", false)); - }, + } sendActivationEmail() { return ajax(userPath("action/send_activation_email"), { type: "POST", data: { username: this.username }, }); - }, + } anonymize() { return ajax(`/admin/users/${this.id}/anonymize.json`, { type: "PUT", }); - }, + } destroy(formData) { return ajax(`/admin/users/${this.id}.json`, { @@ -295,14 +302,14 @@ const AdminUser = User.extend({ .catch(() => { this.find(this.id).then((u) => this.setProperties(u)); }); - }, + } merge(formData) { return ajax(`/admin/users/${this.id}/merge.json`, { type: "POST", data: formData, }); - }, + } loadDetails() { if (this.loadedDetails) { @@ -313,23 +320,29 @@ const AdminUser = User.extend({ const userProperties = Object.assign(result, { loadedDetails: true }); this.setProperties(userProperties); }); - }, + } @discourseComputed("tl3_requirements") tl3Requirements(requirements) { if (requirements) { return this.store.createRecord("tl3Requirements", requirements); } - }, + } @discourseComputed("suspended_by") - suspendedBy: wrapAdmin, + suspendedBy(user) { + return user ? AdminUser.create(user) : null; + } @discourseComputed("silenced_by") - silencedBy: wrapAdmin, + silencedBy(user) { + return user ? AdminUser.create(user) : null; + } @discourseComputed("approved_by") - approvedBy: wrapAdmin, + approvedBy(user) { + return user ? AdminUser.create(user) : null; + } deleteSSORecord() { return ajax(`/admin/users/${this.id}/sso_record.json`, { @@ -339,22 +352,5 @@ const AdminUser = User.extend({ this.set("single_sign_on_record", null); }) .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; + } +} diff --git a/app/assets/javascripts/admin/addon/models/api-key.js b/app/assets/javascripts/admin/addon/models/api-key.js index be5475a4abc..f40d643270b 100644 --- a/app/assets/javascripts/admin/addon/models/api-key.js +++ b/app/assets/javascripts/admin/addon/models/api-key.js @@ -1,24 +1,26 @@ +import { computed } from "@ember/object"; import AdminUser from "admin/models/admin-user"; import RestModel from "discourse/models/rest"; import { ajax } from "discourse/lib/ajax"; -import { computed } from "@ember/object"; import discourseComputed from "discourse-common/utils/decorators"; import { fmt } from "discourse/lib/computed"; -const ApiKey = RestModel.extend({ - user: computed("_user", { - get() { - return this._user; - }, - set(key, value) { - if (value && !(value instanceof AdminUser)) { - this.set("_user", AdminUser.create(value)); - } else { - this.set("_user", value); - } - return this._user; - }, - }), +export default class ApiKey extends RestModel { + @fmt("truncated_key", "%@...") truncatedKey; + + @computed("_user") + get user() { + return this._user; + } + + set user(value) { + if (value && !(value instanceof AdminUser)) { + this.set("_user", AdminUser.create(value)); + } else { + this.set("_user", value); + } + return this._user; + } @discourseComputed("description") shortDescription(description) { @@ -26,32 +28,28 @@ const ApiKey = RestModel.extend({ return description; } return `${description.substring(0, 40)}...`; - }, - - truncatedKey: fmt("truncated_key", "%@..."), + } revoke() { return ajax(`${this.basePath}/revoke`, { type: "POST", }).then((result) => this.setProperties(result.api_key)); - }, + } undoRevoke() { return ajax(`${this.basePath}/undo-revoke`, { type: "POST", }).then((result) => this.setProperties(result.api_key)); - }, + } createProperties() { return this.getProperties("description", "username", "scopes"); - }, + } @discourseComputed() basePath() { return this.store .adapterFor("api-key") .pathFor(this.store, "api-key", this.id); - }, -}); - -export default ApiKey; + } +} diff --git a/app/assets/javascripts/admin/addon/models/backup-status.js b/app/assets/javascripts/admin/addon/models/backup-status.js index dffad0d0609..e9ee065f3e2 100644 --- a/app/assets/javascripts/admin/addon/models/backup-status.js +++ b/app/assets/javascripts/admin/addon/models/backup-status.js @@ -1,12 +1,12 @@ +import { not } from "@ember/object/computed"; import EmberObject from "@ember/object"; import discourseComputed from "discourse-common/utils/decorators"; -import { not } from "@ember/object/computed"; -export default EmberObject.extend({ - restoreDisabled: not("restoreEnabled"), +export default class BackupStatus extends EmberObject { + @not("restoreEnabled") restoreDisabled; @discourseComputed("allowRestore", "isOperationRunning") restoreEnabled(allowRestore, isOperationRunning) { return allowRestore && !isOperationRunning; - }, -}); + } +} diff --git a/app/assets/javascripts/admin/addon/models/backup.js b/app/assets/javascripts/admin/addon/models/backup.js index 717192e8ac3..9708f9589bc 100644 --- a/app/assets/javascripts/admin/addon/models/backup.js +++ b/app/assets/javascripts/admin/addon/models/backup.js @@ -2,25 +2,12 @@ import EmberObject from "@ember/object"; import MessageBus from "message-bus-client"; import { ajax } from "discourse/lib/ajax"; -const Backup = EmberObject.extend({ - destroy() { - 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() { +export default class Backup extends EmberObject { + static find() { return ajax("/admin/backups.json"); - }, + } - start(withUploads) { + static start(withUploads) { if (withUploads === undefined) { withUploads = true; } @@ -31,19 +18,28 @@ Backup.reopenClass({ client_id: MessageBus.clientId, }, }); - }, + } - cancel() { + static cancel() { return ajax("/admin/backups/cancel.json", { type: "DELETE", }); - }, + } - rollback() { + static rollback() { return ajax("/admin/backups/rollback.json", { 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 }, + }); + } +} diff --git a/app/assets/javascripts/admin/addon/models/color-scheme-color.js b/app/assets/javascripts/admin/addon/models/color-scheme-color.js index 24beb9130ca..72efcb32c13 100644 --- a/app/assets/javascripts/admin/addon/models/color-scheme-color.js +++ b/app/assets/javascripts/admin/addon/models/color-scheme-color.js @@ -1,19 +1,19 @@ -import discourseComputed, { - observes, - on, -} from "discourse-common/utils/decorators"; +import discourseComputed from "discourse-common/utils/decorators"; +import { observes, on } from "@ember-decorators/object"; import EmberObject from "@ember/object"; import I18n from "I18n"; 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") startTrackingChanges() { this.set("originals", { hex: this.hex || "FFFFFF" }); // force changed property to be recalculated this.notifyPropertyChange("hex"); - }, + } // Whether value has changed since it was last saved. @discourseComputed("hex") @@ -26,26 +26,23 @@ const ColorSchemeColor = EmberObject.extend({ } 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. @discourseComputed("default_hex", "hex") savedIsOverriden(defaultHex) { return this.originals.hex !== defaultHex; - }, + } revert() { this.set("hex", this.default_hex); - }, + } undo() { if (this.originals) { this.set("hex", this.originals.hex); } - }, + } @discourseComputed("name") translatedName(name) { @@ -54,7 +51,7 @@ const ColorSchemeColor = EmberObject.extend({ } else { return name; } - }, + } @discourseComputed("name") description(name) { @@ -63,7 +60,7 @@ const ColorSchemeColor = EmberObject.extend({ } else { return ""; } - }, + } /** brightness returns a number between 0 (darkest) to 255 (brightest). @@ -90,19 +87,17 @@ const ColorSchemeColor = EmberObject.extend({ 1000 ); } - }, + } @observes("hex") hexValueChanged() { if (this.hex) { this.set("hex", this.hex.toString().replace(/[^0-9a-fA-F]/g, "")); } - }, + } @discourseComputed("hex") valid(hex) { return hex.match(/^([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/) !== null; - }, -}); - -export default ColorSchemeColor; + } +} diff --git a/app/assets/javascripts/admin/addon/models/color-scheme.js b/app/assets/javascripts/admin/addon/models/color-scheme.js index e1b73ad14e8..53f8ea7eeda 100644 --- a/app/assets/javascripts/admin/addon/models/color-scheme.js +++ b/app/assets/javascripts/admin/addon/models/color-scheme.js @@ -1,3 +1,4 @@ +import { not } from "@ember/object/computed"; import { A } from "@ember/array"; import ArrayProxy from "@ember/array/proxy"; import ColorSchemeColor from "admin/models/color-scheme-color"; @@ -5,26 +6,56 @@ import EmberObject from "@ember/object"; import I18n from "I18n"; import { ajax } from "discourse/lib/ajax"; 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() { - this._super(...arguments); + super.init(...arguments); this.startTrackingChanges(); - }, + } @discourseComputed description() { return "" + this.name; - }, + } startTrackingChanges() { this.set("originals", { name: this.name, user_selectable: this.user_selectable, }); - }, + } schemeJson() { const buffer = []; @@ -33,7 +64,7 @@ const ColorScheme = EmberObject.extend({ }); return [`"${this.name}": {`, buffer.join(",\n"), "}"].join("\n"); - }, + } copy() { const newScheme = ColorScheme.create({ @@ -47,7 +78,7 @@ const ColorScheme = EmberObject.extend({ ); }); return newScheme; - }, + } @discourseComputed( "name", @@ -70,7 +101,7 @@ const ColorScheme = EmberObject.extend({ } return false; - }, + } @discourseComputed("changed") disableSave(changed) { @@ -79,9 +110,7 @@ const ColorScheme = EmberObject.extend({ } return !changed || this.saving || this.colors.any((c) => !c.get("valid")); - }, - - newRecord: not("id"), + } save(opts) { if (this.is_base || this.disableSave) { @@ -124,7 +153,7 @@ const ColorScheme = EmberObject.extend({ this.setProperties({ savingStatus: I18n.t("saved"), saving: false }); this.notifyPropertyChange("description"); }); - }, + } updateUserSelectable(value) { if (!this.id) { @@ -137,45 +166,11 @@ const ColorScheme = EmberObject.extend({ dataType: "json", contentType: "application/json", }); - }, + } destroy() { if (this.id) { 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; + } +} diff --git a/app/assets/javascripts/admin/addon/models/email-log.js b/app/assets/javascripts/admin/addon/models/email-log.js index 6565611974a..18034d9f949 100644 --- a/app/assets/javascripts/admin/addon/models/email-log.js +++ b/app/assets/javascripts/admin/addon/models/email-log.js @@ -3,10 +3,8 @@ import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; import getURL from "discourse-common/lib/get-url"; -const EmailLog = EmberObject.extend({}); - -EmailLog.reopenClass({ - create(attrs) { +export default class EmailLog extends EmberObject { + static create(attrs) { attrs = attrs || {}; if (attrs.user) { @@ -17,10 +15,10 @@ EmailLog.reopenClass({ attrs.post_url = getURL(attrs.post_url); } - return this._super(attrs); - }, + return super.create(attrs); + } - findAll(filter, offset) { + static findAll(filter, offset) { filter = filter || {}; offset = offset || 0; @@ -30,7 +28,5 @@ EmailLog.reopenClass({ return ajax(`/admin/email/${status}.json?offset=${offset}`, { data: filter, }).then((logs) => logs.map((log) => EmailLog.create(log))); - }, -}); - -export default EmailLog; + } +} diff --git a/app/assets/javascripts/admin/addon/models/email-preview.js b/app/assets/javascripts/admin/addon/models/email-preview.js index 1a709db82bb..3de69dcb077 100644 --- a/app/assets/javascripts/admin/addon/models/email-preview.js +++ b/app/assets/javascripts/admin/addon/models/email-preview.js @@ -1,25 +1,21 @@ import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; -const EmailPreview = EmberObject.extend({}); - -export function oneWeekAgo() { - return moment().locale("en").subtract(7, "days").format("YYYY-MM-DD"); -} - -EmailPreview.reopenClass({ - findDigest(username, lastSeenAt) { +export default class EmailPreview extends EmberObject { + static findDigest(username, lastSeenAt) { return ajax("/admin/email/preview-digest.json", { data: { last_seen_at: lastSeenAt || oneWeekAgo(), username }, }).then((result) => EmailPreview.create(result)); - }, + } - sendDigest(username, lastSeenAt, email) { + static sendDigest(username, lastSeenAt, email) { return ajax("/admin/email/send-digest.json", { type: "POST", 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"); +} diff --git a/app/assets/javascripts/admin/addon/models/email-settings.js b/app/assets/javascripts/admin/addon/models/email-settings.js index aa4a245f009..cfddf2f6a9a 100644 --- a/app/assets/javascripts/admin/addon/models/email-settings.js +++ b/app/assets/javascripts/admin/addon/models/email-settings.js @@ -1,14 +1,10 @@ import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; -const EmailSettings = EmberObject.extend({}); - -EmailSettings.reopenClass({ - find() { +export default class EmailSettings extends EmberObject { + static find() { return ajax("/admin/email.json").then(function (settings) { return EmailSettings.create(settings); }); - }, -}); - -export default EmailSettings; + } +} diff --git a/app/assets/javascripts/admin/addon/models/email-style.js b/app/assets/javascripts/admin/addon/models/email-style.js index 3dd991d70ac..2824539a7a6 100644 --- a/app/assets/javascripts/admin/addon/models/email-style.js +++ b/app/assets/javascripts/admin/addon/models/email-style.js @@ -1,10 +1,10 @@ import RestModel from "discourse/models/rest"; -export default RestModel.extend({ - changed: false, +export default class EmailStyle extends RestModel { + changed = false; setField(fieldName, value) { this.set(`${fieldName}`, value); this.set("changed", true); - }, -}); + } +} diff --git a/app/assets/javascripts/admin/addon/models/email-template.js b/app/assets/javascripts/admin/addon/models/email-template.js index 19936a6a976..f3d8c514cbd 100644 --- a/app/assets/javascripts/admin/addon/models/email-template.js +++ b/app/assets/javascripts/admin/addon/models/email-template.js @@ -2,12 +2,12 @@ import RestModel from "discourse/models/rest"; import { ajax } from "discourse/lib/ajax"; import { getProperties } from "@ember/object"; -export default RestModel.extend({ +export default class EmailTemplate extends RestModel { revert() { return ajax(`/admin/customize/email_templates/${this.id}`, { type: "DELETE", }).then((result) => getProperties(result.email_template, "subject", "body", "can_revert") ); - }, -}); + } +} diff --git a/app/assets/javascripts/admin/addon/models/flag-type.js b/app/assets/javascripts/admin/addon/models/flag-type.js index 5859584ce7f..3bb399fc2e5 100644 --- a/app/assets/javascripts/admin/addon/models/flag-type.js +++ b/app/assets/javascripts/admin/addon/models/flag-type.js @@ -2,9 +2,9 @@ import I18n from "I18n"; import RestModel from "discourse/models/rest"; import discourseComputed from "discourse-common/utils/decorators"; -export default RestModel.extend({ +export default class FlagType extends RestModel { @discourseComputed("id") name(id) { return I18n.t(`admin.flags.summary.action_type_${id}`, { count: 1 }); - }, -}); + } +} diff --git a/app/assets/javascripts/admin/addon/models/form-template.js b/app/assets/javascripts/admin/addon/models/form-template.js index 782b6a8c317..4999210c931 100644 --- a/app/assets/javascripts/admin/addon/models/form-template.js +++ b/app/assets/javascripts/admin/addon/models/form-template.js @@ -1,53 +1,51 @@ import RestModel from "discourse/models/rest"; import { ajax } from "discourse/lib/ajax"; -export default class FormTemplate extends RestModel {} - -FormTemplate.reopenClass({ - createTemplate(data) { +export default class FormTemplate extends RestModel { + static createTemplate(data) { return ajax("/admin/customize/form-templates.json", { type: "POST", data, }); - }, + } - updateTemplate(id, data) { + static updateTemplate(id, data) { return ajax(`/admin/customize/form-templates/${id}.json`, { type: "PUT", data, }); - }, + } - createOrUpdateTemplate(data) { + static createOrUpdateTemplate(data) { if (data.id) { return this.updateTemplate(data.id, data); } else { return this.createTemplate(data); } - }, + } - deleteTemplate(id) { + static deleteTemplate(id) { return ajax(`/admin/customize/form-templates/${id}.json`, { type: "DELETE", }); - }, + } - findAll() { + static findAll() { return ajax(`/admin/customize/form-templates.json`).then((model) => { 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 model.form_template; }); - }, + } - validateTemplate(data) { + static validateTemplate(data) { return ajax(`/admin/customize/form-templates/preview.json`, { type: "GET", data, }); - }, -}); + } +} diff --git a/app/assets/javascripts/admin/addon/models/incoming-email.js b/app/assets/javascripts/admin/addon/models/incoming-email.js index 8489ae8dd35..2e56e8a8295 100644 --- a/app/assets/javascripts/admin/addon/models/incoming-email.js +++ b/app/assets/javascripts/admin/addon/models/incoming-email.js @@ -2,10 +2,8 @@ import AdminUser from "admin/models/admin-user"; import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; -const IncomingEmail = EmberObject.extend({}); - -IncomingEmail.reopenClass({ - create(attrs) { +export default class IncomingEmail extends EmberObject { + static create(attrs) { attrs = attrs || {}; if (attrs.user) { @@ -13,17 +11,17 @@ IncomingEmail.reopenClass({ } return this._super(attrs); - }, + } - find(id) { + static find(id) { return ajax(`/admin/email/incoming/${id}.json`); - }, + } - findByBounced(id) { + static findByBounced(id) { return ajax(`/admin/email/incoming_from_bounced/${id}.json`); - }, + } - findAll(filter, offset) { + static findAll(filter, offset) { filter = filter || {}; offset = offset || 0; @@ -35,11 +33,9 @@ IncomingEmail.reopenClass({ }).then((incomings) => incomings.map((incoming) => IncomingEmail.create(incoming)) ); - }, + } - loadRawEmail(id) { + static loadRawEmail(id) { return ajax(`/admin/email/incoming/${id}/raw.json`); - }, -}); - -export default IncomingEmail; + } +} diff --git a/app/assets/javascripts/admin/addon/models/permalink.js b/app/assets/javascripts/admin/addon/models/permalink.js index 25a3c90e037..580b111f0ae 100644 --- a/app/assets/javascripts/admin/addon/models/permalink.js +++ b/app/assets/javascripts/admin/addon/models/permalink.js @@ -4,7 +4,15 @@ import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; 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() { return ajax("/admin/permalinks.json", { type: "POST", @@ -14,33 +22,21 @@ const Permalink = EmberObject.extend({ permalink_type_value: this.permalink_type_value, }, }); - }, + } @discourseComputed("category_id") category(category_id) { return Category.findById(category_id); - }, + } @discourseComputed("external_url") linkIsExternal(external_url) { return !DiscourseURL.isInternal(external_url); - }, + } destroy() { return ajax("/admin/permalinks/" + this.id + ".json", { 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; + } +} diff --git a/app/assets/javascripts/admin/addon/models/report.js b/app/assets/javascripts/admin/addon/models/report.js index 9cd68dc7987..dd868a00e02 100644 --- a/app/assets/javascripts/admin/addon/models/report.js +++ b/app/assets/javascripts/admin/addon/models/report.js @@ -19,12 +19,188 @@ import round from "discourse/lib/round"; // and you want to ensure cache is reset export const SCHEMA_VERSION = 4; -const Report = EmberObject.extend({ - average: false, - percent: false, - higher_is_better: true, - description_link: null, - description: null, +export default class Report extends EmberObject { + static 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"; + } + } + + 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) => { + // don’t 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") reportUrl(type, start_date, end_date) { @@ -35,7 +211,7 @@ const Report = EmberObject.extend({ return getURL( `/admin/reports/${type}?start_date=${start_date}&end_date=${end_date}` ); - }, + } valueAt(numDaysAgo) { if (this.data) { @@ -49,7 +225,7 @@ const Report = EmberObject.extend({ } } return 0; - }, + } valueFor(startDaysAgo, endDaysAgo) { if (this.data) { @@ -70,46 +246,46 @@ const Report = EmberObject.extend({ } return round(sum, -2); } - }, + } @discourseComputed("data", "average") todayCount() { return this.valueAt(0); - }, + } @discourseComputed("data", "average") yesterdayCount() { return this.valueAt(1); - }, + } @discourseComputed("data", "average") sevenDaysAgoCount() { return this.valueAt(7); - }, + } @discourseComputed("data", "average") thirtyDaysAgoCount() { return this.valueAt(30); - }, + } @discourseComputed("data", "average") lastSevenDaysCount() { return this.averageCount(7, this.valueFor(1, 7)); - }, + } @discourseComputed("data", "average") lastThirtyDaysCount() { return this.averageCount(30, this.valueFor(1, 30)); - }, + } averageCount(count, value) { return this.average ? value / count : value; - }, + } @discourseComputed("yesterdayCount", "higher_is_better") yesterdayTrend(yesterdayCount, higherIsBetter) { return this._computeTrend(this.valueAt(2), yesterdayCount, higherIsBetter); - }, + } @discourseComputed("lastSevenDaysCount", "higher_is_better") sevenDaysTrend(lastSevenDaysCount, higherIsBetter) { @@ -118,39 +294,39 @@ const Report = EmberObject.extend({ lastSevenDaysCount, higherIsBetter ); - }, + } @discourseComputed("data") currentTotal(data) { return data.reduce((cur, pair) => cur + pair.y, 0); - }, + } @discourseComputed("data", "currentTotal") currentAverage(data, total) { return makeArray(data).length === 0 ? 0 : parseFloat((total / parseFloat(data.length)).toFixed(1)); - }, + } @discourseComputed("trend", "higher_is_better") trendIcon(trend, higherIsBetter) { return this._iconForTrend(trend, higherIsBetter); - }, + } @discourseComputed("sevenDaysTrend", "higher_is_better") sevenDaysTrendIcon(sevenDaysTrend, higherIsBetter) { return this._iconForTrend(sevenDaysTrend, higherIsBetter); - }, + } @discourseComputed("thirtyDaysTrend", "higher_is_better") thirtyDaysTrendIcon(thirtyDaysTrend, higherIsBetter) { return this._iconForTrend(thirtyDaysTrend, higherIsBetter); - }, + } @discourseComputed("yesterdayTrend", "higher_is_better") yesterdayTrendIcon(yesterdayTrend, higherIsBetter) { return this._iconForTrend(yesterdayTrend, higherIsBetter); - }, + } @discourseComputed( "prev_period", @@ -161,7 +337,7 @@ const Report = EmberObject.extend({ trend(prev, currentTotal, currentAverage, higherIsBetter) { const total = this.average ? currentAverage : currentTotal; return this._computeTrend(prev, total, higherIsBetter); - }, + } @discourseComputed( "prev30Days", @@ -180,7 +356,7 @@ const Report = EmberObject.extend({ lastThirtyDaysCount, higherIsBetter ); - }, + } @discourseComputed("type") method(type) { @@ -189,7 +365,7 @@ const Report = EmberObject.extend({ } else { return "sum"; } - }, + } percentChangeString(val1, val2) { const change = this._computeChange(val1, val2); @@ -201,7 +377,7 @@ const Report = EmberObject.extend({ } else { return change.toFixed(0) + "%"; } - }, + } @discourseComputed("prev_period", "currentTotal", "currentAverage") trendTitle(prev, currentTotal, currentAverage) { @@ -224,7 +400,7 @@ const Report = EmberObject.extend({ prev, current, }); - }, + } changeTitle(valAtT1, valAtT2, prevPeriodString) { const change = this.percentChangeString(valAtT1, valAtT2); @@ -234,12 +410,12 @@ const Report = EmberObject.extend({ } title += `Was ${number(valAtT1)} ${prevPeriodString}.`; return title; - }, + } @discourseComputed("yesterdayCount") yesterdayCountTitle(yesterdayCount) { return this.changeTitle(this.valueAt(2), yesterdayCount, "two days ago"); - }, + } @discourseComputed("lastSevenDaysCount") sevenDaysCountTitle(lastSevenDaysCount) { @@ -248,12 +424,12 @@ const Report = EmberObject.extend({ lastSevenDaysCount, "two weeks ago" ); - }, + } @discourseComputed("prev30Days", "prev_period") canDisplayTrendIcon(prev30Days, prev_period) { return prev30Days ?? prev_period; - }, + } @discourseComputed("prev30Days", "prev_period", "lastThirtyDaysCount") thirtyDaysCountTitle(prev30Days, prev_period, lastThirtyDaysCount) { @@ -262,12 +438,12 @@ const Report = EmberObject.extend({ lastThirtyDaysCount, "in the previous 30 day period" ); - }, + } @discourseComputed("data") sortedData(data) { return this.xAxisIsDate ? data.toArray().reverse() : data.toArray(); - }, + } @discourseComputed("data") xAxisIsDate() { @@ -275,7 +451,7 @@ const Report = EmberObject.extend({ return false; } return this.data && this.data[0].x.match(/\d{4}-\d{1,2}-\d{1,2}/); - }, + } @discourseComputed("labels") computedLabels(labels) { @@ -359,7 +535,7 @@ const Report = EmberObject.extend({ }, }; }); - }, + } _userLabel(properties, row) { const username = row[properties.username]; @@ -388,7 +564,7 @@ const Report = EmberObject.extend({ value: username, formattedValue: username ? formattedValue() : "—", }; - }, + } _topicLabel(properties, row) { const topicTitle = row[properties.title]; @@ -403,7 +579,7 @@ const Report = EmberObject.extend({ value: topicTitle, formattedValue: topicTitle ? formattedValue() : "—", }; - }, + } _postLabel(properties, row) { const postTitle = row[properties.truncated_raw]; @@ -419,21 +595,21 @@ const Report = EmberObject.extend({ ? `${escapeExpression(postTitle)}` : "—", }; - }, + } _secondsLabel(value) { return { value: toNumber(value), formattedValue: durationTiny(value), }; - }, + } _percentLabel(value) { return { value: toNumber(value), formattedValue: value ? `${value}%` : "—", }; - }, + } _numberLabel(value, options = {}) { const formatNumbers = isEmpty(options.formatNumbers) @@ -446,21 +622,21 @@ const Report = EmberObject.extend({ value: toNumber(value), formattedValue: value ? formattedValue() : "—", }; - }, + } _bytesLabel(value) { return { value: toNumber(value), formattedValue: I18n.toHumanSize(value), }; - }, + } _dateLabel(value, date, format = "LL") { return { value, formattedValue: value ? date.format(format) : "—", }; - }, + } _textLabel(value) { const escaped = escapeExpression(value); @@ -469,7 +645,7 @@ const Report = EmberObject.extend({ value, formattedValue: value ? escaped : "—", }; - }, + } _linkLabel(properties, row) { const property = properties[0]; @@ -484,11 +660,11 @@ const Report = EmberObject.extend({ value, formattedValue: value ? formattedValue(value, row[properties[1]]) : "—", }; - }, + } _computeChange(valAtT1, valAtT2) { return ((valAtT2 - valAtT1) / valAtT1) * 100; - }, + } _computeTrend(valAtT1, valAtT2, higherIsBetter) { const change = this._computeChange(valAtT1, valAtT2); @@ -504,7 +680,7 @@ const Report = EmberObject.extend({ } else if (change < -2) { return higherIsBetter ? "trending-down" : "trending-up"; } - }, + } _iconForTrend(trend, higherIsBetter) { switch (trend) { @@ -519,8 +695,8 @@ const Report = EmberObject.extend({ default: return "minus"; } - }, -}); + } +} export const WEEKLY_LIMIT_DAYS = 365; 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 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) => { - // don’t 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; diff --git a/app/assets/javascripts/admin/addon/models/screened-email.js b/app/assets/javascripts/admin/addon/models/screened-email.js index 62e985949df..8d7a3161ad8 100644 --- a/app/assets/javascripts/admin/addon/models/screened-email.js +++ b/app/assets/javascripts/admin/addon/models/screened-email.js @@ -3,21 +3,8 @@ import I18n from "I18n"; import { ajax } from "discourse/lib/ajax"; import discourseComputed from "discourse-common/utils/decorators"; -const ScreenedEmail = EmberObject.extend({ - @discourseComputed("action") - actionName(action) { - return I18n.t("admin.logs.screened_actions." + action); - }, - - clearBlock() { - return ajax("/admin/logs/screened_emails/" + this.id, { - type: "DELETE", - }); - }, -}); - -ScreenedEmail.reopenClass({ - findAll() { +export default class ScreenedEmail extends EmberObject { + static findAll() { return ajax("/admin/logs/screened_emails.json").then(function ( screened_emails ) { @@ -25,7 +12,16 @@ ScreenedEmail.reopenClass({ 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", + }); + } +} diff --git a/app/assets/javascripts/admin/addon/models/screened-ip-address.js b/app/assets/javascripts/admin/addon/models/screened-ip-address.js index 0fe7578f89f..87979087aaa 100644 --- a/app/assets/javascripts/admin/addon/models/screened-ip-address.js +++ b/app/assets/javascripts/admin/addon/models/screened-ip-address.js @@ -1,21 +1,28 @@ +import { equal } from "@ember/object/computed"; import EmberObject from "@ember/object"; import I18n from "I18n"; import { ajax } from "discourse/lib/ajax"; 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") actionName(actionName) { return I18n.t(`admin.logs.screened_ips.actions.${actionName}`); - }, - - isBlocked: equal("action_name", "block"), + } @discourseComputed("ip_address") isRange(ipAddress) { return ipAddress.indexOf("/") > 0; - }, + } save() { return ajax( @@ -30,23 +37,11 @@ const ScreenedIpAddress = EmberObject.extend({ }, } ); - }, + } destroy() { return ajax("/admin/logs/screened_ip_addresses/" + this.id + ".json", { 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; + } +} diff --git a/app/assets/javascripts/admin/addon/models/screened-url.js b/app/assets/javascripts/admin/addon/models/screened-url.js index 9a0d4e1b737..3d2c5f97941 100644 --- a/app/assets/javascripts/admin/addon/models/screened-url.js +++ b/app/assets/javascripts/admin/addon/models/screened-url.js @@ -3,15 +3,8 @@ import I18n from "I18n"; import { ajax } from "discourse/lib/ajax"; import discourseComputed from "discourse-common/utils/decorators"; -const ScreenedUrl = EmberObject.extend({ - @discourseComputed("action") - actionName(action) { - return I18n.t("admin.logs.screened_actions." + action); - }, -}); - -ScreenedUrl.reopenClass({ - findAll() { +export default class ScreenedUrl extends EmberObject { + static findAll() { return ajax("/admin/logs/screened_urls.json").then(function ( screened_urls ) { @@ -19,7 +12,10 @@ ScreenedUrl.reopenClass({ return ScreenedUrl.create(b); }); }); - }, -}); + } -export default ScreenedUrl; + @discourseComputed("action") + actionName(action) { + return I18n.t("admin.logs.screened_actions." + action); + } +} diff --git a/app/assets/javascripts/admin/addon/models/site-setting.js b/app/assets/javascripts/admin/addon/models/site-setting.js index 49ed58366e1..6cd7852834e 100644 --- a/app/assets/javascripts/admin/addon/models/site-setting.js +++ b/app/assets/javascripts/admin/addon/models/site-setting.js @@ -4,22 +4,8 @@ import Setting from "admin/mixins/setting-object"; import { ajax } from "discourse/lib/ajax"; import discourseComputed from "discourse-common/utils/decorators"; -const SiteSetting = EmberObject.extend(Setting, { - @discourseComputed("setting") - staffLogFilter(setting) { - if (!setting) { - return; - } - - return { - subject: setting, - action_name: "change_site_setting", - }; - }, -}); - -SiteSetting.reopenClass({ - findAll() { +export default class SiteSetting extends EmberObject.extend(Setting) { + static findAll() { return ajax("/admin/site_settings").then(function (settings) { // Group the results by category const categories = {}; @@ -38,9 +24,9 @@ SiteSetting.reopenClass({ }; }); }); - }, + } - update(key, value, opts = {}) { + static update(key, value, opts = {}) { const data = {}; data[key] = value; @@ -49,7 +35,17 @@ SiteSetting.reopenClass({ } 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", + }; + } +} diff --git a/app/assets/javascripts/admin/addon/models/site-text.js b/app/assets/javascripts/admin/addon/models/site-text.js index c25a5b30a00..916030b8d3a 100644 --- a/app/assets/javascripts/admin/addon/models/site-text.js +++ b/app/assets/javascripts/admin/addon/models/site-text.js @@ -2,10 +2,10 @@ import RestModel from "discourse/models/rest"; import { ajax } from "discourse/lib/ajax"; import { getProperties } from "@ember/object"; -export default RestModel.extend({ +export default class SiteText extends RestModel { revert(locale) { return ajax(`/admin/customize/site_texts/${this.id}?locale=${locale}`, { type: "DELETE", }).then((result) => getProperties(result.site_text, "value", "can_revert")); - }, -}); + } +} diff --git a/app/assets/javascripts/admin/addon/models/staff-action-log.js b/app/assets/javascripts/admin/addon/models/staff-action-log.js index 70d86c41e77..4eb7864dd44 100644 --- a/app/assets/javascripts/admin/addon/models/staff-action-log.js +++ b/app/assets/javascripts/admin/addon/models/staff-action-log.js @@ -11,13 +11,36 @@ function format(label, value, escape = true) { : ""; } -const StaffActionLog = RestModel.extend({ - showFullDetails: false, +export default class StaffActionLog extends RestModel { + 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") actionName(actionName) { return I18n.t(`admin.logs.staff_actions.actions.${actionName}`); - }, + } @discourseComputed( "email", @@ -72,42 +95,15 @@ const StaffActionLog = RestModel.extend({ const formatted = lines.filter((l) => l.length > 0).join("
"); return formatted.length > 0 ? formatted + "
" : ""; - }, + } @discourseComputed("details") useModalForDetails(details) { return details && details.length > 100; - }, + } @discourseComputed("action_name") useCustomModalForDetails(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; + } +} diff --git a/app/assets/javascripts/admin/addon/models/theme-settings.js b/app/assets/javascripts/admin/addon/models/theme-settings.js index d91c3e583ef..f61da7c2c0e 100644 --- a/app/assets/javascripts/admin/addon/models/theme-settings.js +++ b/app/assets/javascripts/admin/addon/models/theme-settings.js @@ -1,4 +1,4 @@ import EmberObject from "@ember/object"; import Setting from "admin/mixins/setting-object"; -export default EmberObject.extend(Setting, {}); +export default class ThemeSettings extends EmberObject.extend(Setting) {} diff --git a/app/assets/javascripts/admin/addon/models/theme.js b/app/assets/javascripts/admin/addon/models/theme.js index a7ac122c04c..a4b7d6b64b5 100644 --- a/app/assets/javascripts/admin/addon/models/theme.js +++ b/app/assets/javascripts/admin/addon/models/theme.js @@ -13,11 +13,13 @@ export const THEMES = "themes"; export const COMPONENTS = "components"; const SETTINGS_TYPE_ID = 5; -const Theme = RestModel.extend({ - isActive: or("default", "user_selectable"), - isPendingUpdates: gt("remote_theme.commits_behind", 0), - hasEditedFields: gt("editedFields.length", 0), - hasParents: gt("parent_themes.length", 0), +class Theme extends RestModel { + @or("default", "user_selectable") isActive; + @gt("remote_theme.commits_behind", 0) isPendingUpdates; + @gt("editedFields.length", 0) hasEditedFields; + @gt("parent_themes.length", 0) hasParents; + + changed = false; @discourseComputed("theme_fields.[]") targets() { @@ -45,7 +47,7 @@ const Theme = RestModel.extend({ target["error"] = this.hasError(target.name); return target; }); - }, + } @discourseComputed("theme_fields.[]") fieldNames() { @@ -84,7 +86,7 @@ const Theme = RestModel.extend({ ], extra_scss: scss_fields, }; - }, + } @discourseComputed( "fieldNames", @@ -118,7 +120,7 @@ const Theme = RestModel.extend({ }); }); return hash; - }, + } @discourseComputed("theme_fields") themeFields(fields) { @@ -134,7 +136,7 @@ const Theme = RestModel.extend({ } }); return hash; - }, + } @discourseComputed("theme_fields", "theme_fields.[]") uploads(fields) { @@ -144,32 +146,32 @@ const Theme = RestModel.extend({ return fields.filter( (f) => f.target === "common" && f.type_id === THEME_UPLOAD_VAR ); - }, + } @discourseComputed("theme_fields", "theme_fields.@each.error") isBroken(fields) { return ( fields && fields.any((field) => field.error && field.error.length > 0) ); - }, + } @discourseComputed("theme_fields.[]") editedFields(fields) { return fields.filter( (field) => !isBlank(field.value) && field.type_id !== SETTINGS_TYPE_ID ); - }, + } @discourseComputed("remote_theme.last_error_text") remoteError(errorText) { if (errorText && errorText.length > 0) { return errorText; } - }, + } getKey(field) { return `${field.target} ${field.name}`; - }, + } hasEdited(target, name) { if (name) { @@ -180,27 +182,27 @@ const Theme = RestModel.extend({ (field) => field.target === target && !isEmpty(field.value) ); } - }, + } hasError(target, name) { return this.theme_fields .filter((f) => f.target === target && (!name || name === f.name)) .any((f) => f.error); - }, + } getError(target, name) { let themeFields = this.themeFields; let key = this.getKey({ target, name }); let field = themeFields[key]; return field ? field.error : ""; - }, + } getField(target, name) { let themeFields = this.themeFields; let key = this.getKey({ target, name }); let field = themeFields[key]; return field ? field.value : ""; - }, + } removeField(field) { this.set("changed", true); @@ -209,7 +211,7 @@ const Theme = RestModel.extend({ field.value = null; return this.saveChanges("theme_fields"); - }, + } setField(target, name, value, upload_id, type_id) { this.set("changed", true); @@ -249,25 +251,25 @@ const Theme = RestModel.extend({ this.notifyPropertyChange("theme_fields.[]"); } } - }, + } @discourseComputed("childThemes.[]") child_theme_ids(childThemes) { if (childThemes) { return childThemes.map((theme) => get(theme, "id")); } - }, + } @discourseComputed("recentlyInstalled", "component", "hasParents") warnUnassignedComponent(recent, component, hasParents) { return recent && component && !hasParents; - }, + } removeChildTheme(theme) { const childThemes = this.childThemes; childThemes.removeObject(theme); return this.saveChanges("child_theme_ids"); - }, + } addChildTheme(theme) { let childThemes = this.childThemes; @@ -278,7 +280,7 @@ const Theme = RestModel.extend({ childThemes.removeObject(theme); childThemes.pushObject(theme); return this.saveChanges("child_theme_ids"); - }, + } addParentTheme(theme) { let parentThemes = this.parentThemes; @@ -287,38 +289,36 @@ const Theme = RestModel.extend({ this.set("parentThemes", parentThemes); } parentThemes.addObject(theme); - }, + } checkForUpdates() { return this.save({ remote_check: true }).then(() => this.set("changed", false) ); - }, + } updateToLatest() { return this.save({ remote_update: true }).then(() => this.set("changed", false) ); - }, - - changed: false, + } saveChanges() { const hash = this.getProperties.apply(this, arguments); return this.save(hash) .finally(() => this.set("changed", false)) .catch(popupAjaxError); - }, + } saveSettings(name, value) { const settings = {}; settings[name] = value; return this.save({ settings }); - }, + } saveTranslation(name, value) { return this.save({ translations: { [name]: value } }); - }, -}); + } +} export default Theme; diff --git a/app/assets/javascripts/admin/addon/models/tl3-requirements.js b/app/assets/javascripts/admin/addon/models/tl3-requirements.js index 920d6e5f665..43a41362369 100644 --- a/app/assets/javascripts/admin/addon/models/tl3-requirements.js +++ b/app/assets/javascripts/admin/addon/models/tl3-requirements.js @@ -1,21 +1,21 @@ import EmberObject from "@ember/object"; import discourseComputed from "discourse-common/utils/decorators"; -export default EmberObject.extend({ +export default class Tl3Requirements extends EmberObject { @discourseComputed("days_visited", "time_period") days_visited_percent(daysVisited, timePeriod) { return Math.round((daysVisited * 100) / timePeriod); - }, + } @discourseComputed("min_days_visited", "time_period") min_days_visited_percent(minDaysVisited, timePeriod) { return Math.round((minDaysVisited * 100) / timePeriod); - }, + } @discourseComputed("num_topics_replied_to", "min_topics_replied_to") capped_topics_replied_to(numReplied, minReplied) { return numReplied > minReplied; - }, + } @discourseComputed( "days_visited", @@ -71,5 +71,5 @@ export default EmberObject.extend({ silenced: this.get("penalty_counts.silenced") === 0, suspended: this.get("penalty_counts.suspended") === 0, }; - }, -}); + } +} diff --git a/app/assets/javascripts/admin/addon/models/user-field.js b/app/assets/javascripts/admin/addon/models/user-field.js index 53b92a63fd9..5a8bdea1832 100644 --- a/app/assets/javascripts/admin/addon/models/user-field.js +++ b/app/assets/javascripts/admin/addon/models/user-field.js @@ -2,14 +2,8 @@ import EmberObject from "@ember/object"; import RestModel from "discourse/models/rest"; import { i18n } from "discourse/lib/computed"; -const UserField = RestModel.extend(); - -const UserFieldType = EmberObject.extend({ - name: i18n("id", "admin.user_fields.field_types.%@"), -}); - -UserField.reopenClass({ - fieldTypes() { +export default class UserField extends RestModel { + static fieldTypes() { if (!this._fieldTypes) { this._fieldTypes = [ UserFieldType.create({ id: "text" }), @@ -20,11 +14,13 @@ UserField.reopenClass({ } return this._fieldTypes; - }, + } - fieldTypeById(id) { + static fieldTypeById(id) { return this.fieldTypes().findBy("id", id); - }, -}); + } +} -export default UserField; +class UserFieldType extends EmberObject { + @i18n("id", "admin.user_fields.field_types.%@") name; +} diff --git a/app/assets/javascripts/admin/addon/models/version-check.js b/app/assets/javascripts/admin/addon/models/version-check.js index edf6ad5e0e6..baf029c3c47 100644 --- a/app/assets/javascripts/admin/addon/models/version-check.js +++ b/app/assets/javascripts/admin/addon/models/version-check.js @@ -2,43 +2,39 @@ import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; 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") noCheckPerformed(updatedAt) { return updatedAt === null; - }, + } @discourseComputed("missing_versions_count") upToDate(missingVersionsCount) { return missingVersionsCount === 0 || missingVersionsCount === null; - }, + } @discourseComputed("missing_versions_count") behindByOneVersion(missingVersionsCount) { return missingVersionsCount === 1; - }, + } @discourseComputed("installed_sha") gitLink(installedSHA) { if (installedSHA) { return `https://github.com/discourse/discourse/commits/${installedSHA}`; } - }, + } @discourseComputed("installed_sha") shortSha(installedSHA) { if (installedSHA) { return installedSHA.slice(0, 10); } - }, -}); - -VersionCheck.reopenClass({ - find() { - return ajax("/admin/version_check").then((json) => - VersionCheck.create(json) - ); - }, -}); - -export default VersionCheck; + } +} diff --git a/app/assets/javascripts/admin/addon/models/watched-word.js b/app/assets/javascripts/admin/addon/models/watched-word.js index ceb9317f369..a6de62cc9db 100644 --- a/app/assets/javascripts/admin/addon/models/watched-word.js +++ b/app/assets/javascripts/admin/addon/models/watched-word.js @@ -2,34 +2,8 @@ import EmberObject from "@ember/object"; import I18n from "I18n"; import { ajax } from "discourse/lib/ajax"; -const WatchedWord = EmberObject.extend({ - 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", - }); - }, -}); - -WatchedWord.reopenClass({ - findAll() { +export default class WatchedWord extends EmberObject { + static findAll() { return ajax("/admin/customize/watched_words.json").then((list) => { 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", + }); + } +} diff --git a/app/assets/javascripts/admin/addon/models/web-hook.js b/app/assets/javascripts/admin/addon/models/web-hook.js index 500311bec80..c955d67ae98 100644 --- a/app/assets/javascripts/admin/addon/models/web-hook.js +++ b/app/assets/javascripts/admin/addon/models/web-hook.js @@ -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 Group from "discourse/models/group"; import RestModel from "discourse/models/rest"; import Site from "discourse/models/site"; import { isEmpty } from "@ember/utils"; -export default RestModel.extend({ - content_type: 1, // json - last_delivery_status: 1, // inactive - wildcard_web_hook: false, - verify_certificate: true, - active: false, - web_hook_event_types: null, - groupsFilterInName: null, +export default class WebHook extends RestModel { + content_type = 1; // json + last_delivery_status = 1; // inactive + wildcard_web_hook = false; + verify_certificate = true; + active = false; + web_hook_event_types = null; + groupsFilterInName = null; - @discourseComputed("wildcard_web_hook") - webhookType: { - get(wildcard) { - return wildcard ? "wildcard" : "individual"; - }, - set(value) { - this.set("wildcard_web_hook", value === "wildcard"); - }, - }, + @computed("wildcard_web_hook") + get wildcard() { + return this.wildcard_web_hook ? "wildcard" : "individual"; + } + + set wildcard(value) { + this.set("wildcard_web_hook", value === "wildcard"); + } @discourseComputed("category_ids") categories(categoryIds) { return Category.findByIds(categoryIds); - }, + } @observes("group_ids") updateGroupsFilter() { @@ -41,11 +42,11 @@ export default RestModel.extend({ return groupNames; }, []) ); - }, + } groupFinder(term) { return Group.findAll({ term, ignore_automatic: false }); - }, + } @discourseComputed("wildcard_web_hook", "web_hook_event_types.[]") description(isWildcardWebHook, types) { @@ -57,7 +58,7 @@ export default RestModel.extend({ }); return isWildcardWebHook ? "*" : desc; - }, + } createProperties() { const types = this.web_hook_event_types; @@ -92,9 +93,9 @@ export default RestModel.extend({ return groupIds; }, []), }; - }, + } updateProperties() { return this.createProperties(); - }, -}); + } +}