Compare commits
65
Commits
restructure
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc68d6e230 | ||
|
|
b521d3e909 | ||
|
|
e9c3c335f2 | ||
|
|
0171ad8d3a | ||
|
|
7d34144615 | ||
|
|
8a3263d050 | ||
|
|
e51aad3bfd | ||
|
|
fcd734079b | ||
|
|
a98a223a35 | ||
|
|
123dc9e6d8 | ||
|
|
2f3916c761 | ||
|
|
6a5bfcc782 | ||
|
|
32ccafecde | ||
|
|
1f70537968 | ||
|
|
6aab733bb9 | ||
|
|
6ceba62e98 | ||
|
|
44b17146c0 | ||
|
|
00298bf01a | ||
|
|
7685ebf396 | ||
|
|
4506b0b837 | ||
|
|
0400165798 | ||
|
|
119d331759 | ||
|
|
e28f97a0f4 | ||
|
|
1d3baa5519 | ||
|
|
21de3a2b10 | ||
|
|
c91c456187 | ||
|
|
e42b90507e | ||
|
|
38354f2a2f | ||
|
|
fc109c75c4 | ||
|
|
35cc34ab17 | ||
|
|
95993e7d93 | ||
|
|
10093e0a9f | ||
|
|
02f602236a | ||
|
|
da38a4c053 | ||
|
|
ec53a0d6b8 | ||
|
|
9b72130fdf | ||
|
|
a38fbd0935 | ||
|
|
ea9a0def55 | ||
|
|
81843e8c98 | ||
|
|
114639d2e7 | ||
|
|
5f1e07c556 | ||
|
|
f5c1b6da59 | ||
|
|
6cd52a4966 | ||
|
|
554f03f3da | ||
|
|
c4227de1b5 | ||
|
|
84d9b1a6da | ||
|
|
062efc8a54 | ||
|
|
32f18893ec | ||
|
|
b0c95114ea | ||
|
|
1677f7ae39 | ||
|
|
751916b8e3 | ||
|
|
9581367239 | ||
|
|
6b5412826f | ||
|
|
6f8ff34ffa | ||
|
|
19ac017dd4 | ||
|
|
429c9644de | ||
|
|
de7d8ce497 | ||
|
|
51af568c92 | ||
|
|
1d39cd8c80 | ||
|
|
36f4ebc64b | ||
|
|
789be84744 | ||
|
|
c88bb59d81 | ||
|
|
5ad841de0b | ||
|
|
0948d6b19e | ||
|
|
3828578d5d |
@@ -1,2 +1,7 @@
|
|||||||
|
< 3.5.0.beta8-dev: e51aad3bfd41cf2cb9557e025e833122a9f6c892
|
||||||
|
< 3.5.0.beta5-dev: bd9af0b9a577bfd2c01cc8b81a782a4e8b81b9c5
|
||||||
|
< 3.5.0.beta1-dev: 6ceba62e985223c269782c4bc9a1bdc4a5adba28
|
||||||
|
< 3.4.0.beta2-dev: 7685ebf396c93e8accc5a76a81fcec4384a73fa3
|
||||||
|
< 3.4.0.beta1-dev: da38a4c053b68d7076db4441cfe86b473979945d
|
||||||
|
< 3.3.0.beta1-dev: 062efc8a547c19474eaeefae464837d63a5e5fb3
|
||||||
3.1.999: 30c49eb50d6d16fcf82bace3da0e1972b7b220c0
|
3.1.999: 30c49eb50d6d16fcf82bace3da0e1972b7b220c0
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
module.exports = require("@discourse/lint-configs/eslint");
|
|
||||||
+80
-32
@@ -1,54 +1,102 @@
|
|||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
ast (2.4.2)
|
activesupport (8.0.2)
|
||||||
json (2.6.3)
|
base64
|
||||||
language_server-protocol (3.17.0.3)
|
benchmark (>= 0.3)
|
||||||
parallel (1.23.0)
|
bigdecimal
|
||||||
parser (3.2.2.4)
|
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||||
|
connection_pool (>= 2.2.5)
|
||||||
|
drb
|
||||||
|
i18n (>= 1.6, < 2)
|
||||||
|
logger (>= 1.4.2)
|
||||||
|
minitest (>= 5.1)
|
||||||
|
securerandom (>= 0.3)
|
||||||
|
tzinfo (~> 2.0, >= 2.0.5)
|
||||||
|
uri (>= 0.13.1)
|
||||||
|
ast (2.4.3)
|
||||||
|
base64 (0.3.0)
|
||||||
|
benchmark (0.4.1)
|
||||||
|
bigdecimal (3.2.0)
|
||||||
|
concurrent-ruby (1.3.5)
|
||||||
|
connection_pool (2.5.3)
|
||||||
|
drb (2.2.3)
|
||||||
|
i18n (1.14.7)
|
||||||
|
concurrent-ruby (~> 1.0)
|
||||||
|
json (2.12.2)
|
||||||
|
language_server-protocol (3.17.0.5)
|
||||||
|
lint_roller (1.1.0)
|
||||||
|
logger (1.7.0)
|
||||||
|
minitest (5.25.5)
|
||||||
|
parallel (1.27.0)
|
||||||
|
parser (3.3.8.0)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
racc
|
racc
|
||||||
prettier_print (1.2.1)
|
prettier_print (1.2.1)
|
||||||
racc (1.7.3)
|
prism (1.4.0)
|
||||||
|
racc (1.8.1)
|
||||||
|
rack (3.1.16)
|
||||||
rainbow (3.1.1)
|
rainbow (3.1.1)
|
||||||
regexp_parser (2.8.2)
|
regexp_parser (2.10.0)
|
||||||
rexml (3.2.6)
|
rubocop (1.75.8)
|
||||||
rubocop (1.57.2)
|
|
||||||
json (~> 2.3)
|
json (~> 2.3)
|
||||||
language_server-protocol (>= 3.17.0)
|
language_server-protocol (~> 3.17.0.2)
|
||||||
|
lint_roller (~> 1.1.0)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 3.2.2.4)
|
parser (>= 3.3.0.2)
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
regexp_parser (>= 1.8, < 3.0)
|
regexp_parser (>= 2.9.3, < 3.0)
|
||||||
rexml (>= 3.2.5, < 4.0)
|
rubocop-ast (>= 1.44.0, < 2.0)
|
||||||
rubocop-ast (>= 1.28.1, < 2.0)
|
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 2.4.0, < 3.0)
|
unicode-display_width (>= 2.4.0, < 4.0)
|
||||||
rubocop-ast (1.30.0)
|
rubocop-ast (1.44.1)
|
||||||
parser (>= 3.2.1.0)
|
parser (>= 3.3.7.2)
|
||||||
rubocop-capybara (2.19.0)
|
prism (~> 1.4)
|
||||||
rubocop (~> 1.41)
|
rubocop-capybara (2.22.1)
|
||||||
rubocop-discourse (3.4.0)
|
lint_roller (~> 1.1)
|
||||||
rubocop (>= 1.1.0)
|
rubocop (~> 1.72, >= 1.72.1)
|
||||||
rubocop-rspec (>= 2.0.0)
|
rubocop-discourse (3.12.1)
|
||||||
rubocop-factory_bot (2.24.0)
|
activesupport (>= 6.1)
|
||||||
rubocop (~> 1.33)
|
lint_roller (>= 1.1.0)
|
||||||
rubocop-rspec (2.25.0)
|
rubocop (>= 1.73.2)
|
||||||
rubocop (~> 1.40)
|
rubocop-capybara (>= 2.22.0)
|
||||||
rubocop-capybara (~> 2.17)
|
rubocop-factory_bot (>= 2.27.0)
|
||||||
rubocop-factory_bot (~> 2.22)
|
rubocop-rails (>= 2.30.3)
|
||||||
|
rubocop-rspec (>= 3.0.1)
|
||||||
|
rubocop-rspec_rails (>= 2.31.0)
|
||||||
|
rubocop-factory_bot (2.27.1)
|
||||||
|
lint_roller (~> 1.1)
|
||||||
|
rubocop (~> 1.72, >= 1.72.1)
|
||||||
|
rubocop-rails (2.32.0)
|
||||||
|
activesupport (>= 4.2.0)
|
||||||
|
lint_roller (~> 1.1)
|
||||||
|
rack (>= 1.1)
|
||||||
|
rubocop (>= 1.75.0, < 2.0)
|
||||||
|
rubocop-ast (>= 1.44.0, < 2.0)
|
||||||
|
rubocop-rspec (3.6.0)
|
||||||
|
lint_roller (~> 1.1)
|
||||||
|
rubocop (~> 1.72, >= 1.72.1)
|
||||||
|
rubocop-rspec_rails (2.31.0)
|
||||||
|
lint_roller (~> 1.1)
|
||||||
|
rubocop (~> 1.72, >= 1.72.1)
|
||||||
|
rubocop-rspec (~> 3.5)
|
||||||
ruby-progressbar (1.13.0)
|
ruby-progressbar (1.13.0)
|
||||||
|
securerandom (0.4.1)
|
||||||
syntax_tree (6.2.0)
|
syntax_tree (6.2.0)
|
||||||
prettier_print (>= 1.2.0)
|
prettier_print (>= 1.2.0)
|
||||||
unicode-display_width (2.5.0)
|
tzinfo (2.0.6)
|
||||||
|
concurrent-ruby (~> 1.0)
|
||||||
|
unicode-display_width (3.1.4)
|
||||||
|
unicode-emoji (~> 4.0, >= 4.0.4)
|
||||||
|
unicode-emoji (4.0.4)
|
||||||
|
uri (1.0.3)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
arm64-darwin-21
|
ruby
|
||||||
x86_64-linux
|
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
rubocop-discourse
|
rubocop-discourse
|
||||||
syntax_tree
|
syntax_tree
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.4.21
|
2.6.9
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
# Official Discourse Advertising Plugin
|
# Official Discourse Advertising Plugin
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> This plugin has now been bundled into Discourse core. See: https://meta.discourse.org/t/bundling-more-popular-plugins-with-discourse-core/373574
|
||||||
|
|
||||||
Official Plugin Topic & Documentation: https://meta.discourse.org/t/official-advertising-ad-plugin-for-discourse/33734
|
Official Plugin Topic & Documentation: https://meta.discourse.org/t/official-advertising-ad-plugin-for-discourse/33734
|
||||||
|
|
||||||
This is the official Discourse advertising plugin. It allows advertisements to be served by supported advertising platforms for users with a Discourse forum.
|
This is the official Discourse advertising plugin. It allows advertisements to be served by supported advertising platforms for users with a Discourse forum.
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import CategorySelector from "select-kit/components/category-selector";
|
||||||
|
|
||||||
|
export default class HouseAdsCategorySelector extends CategorySelector {
|
||||||
|
get value() {
|
||||||
|
return this.selectedCategories.map((c) => c.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { computed } from "@ember/object";
|
||||||
|
import { classNames } from "@ember-decorators/component";
|
||||||
|
import { makeArray } from "discourse/lib/helpers";
|
||||||
|
import MultiSelectComponent from "select-kit/components/multi-select";
|
||||||
|
|
||||||
|
@classNames("house-ads-chooser")
|
||||||
|
export default class HouseAdsChooser extends MultiSelectComponent {
|
||||||
|
filterable = true;
|
||||||
|
filterPlaceholder = "admin.adplugin.house_ads.filter_placeholder";
|
||||||
|
tokenSeparator = "|";
|
||||||
|
allowCreate = false;
|
||||||
|
allowAny = false;
|
||||||
|
settingValue = "";
|
||||||
|
valueAttribute = null;
|
||||||
|
nameProperty = null;
|
||||||
|
|
||||||
|
@computed("settingValue")
|
||||||
|
get value() {
|
||||||
|
return this.settingValue
|
||||||
|
.toString()
|
||||||
|
.split(this.tokenSeparator)
|
||||||
|
.filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
computeValues() {
|
||||||
|
return this.settingValue.split(this.tokenSeparator).filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed("choices")
|
||||||
|
get content() {
|
||||||
|
return makeArray(this.choices);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
|
import { mapBy } from "@ember/object/computed";
|
||||||
|
import { classNames } from "@ember-decorators/component";
|
||||||
|
import DButton from "discourse/components/d-button";
|
||||||
|
import { makeArray } from "discourse/lib/helpers";
|
||||||
|
import HouseAdsChooser from "./house-ads-chooser";
|
||||||
|
import HouseAdsSetting from "./house-ads-setting";
|
||||||
|
|
||||||
|
@classNames("house-ads-setting house-ads-list-setting")
|
||||||
|
export default class HouseAdsListSetting extends HouseAdsSetting {
|
||||||
|
@mapBy("allAds", "name") adNames;
|
||||||
|
|
||||||
|
@action
|
||||||
|
changeAdValue(value) {
|
||||||
|
const settingValue = makeArray(value).join("|");
|
||||||
|
this.set("adValue", settingValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<label for={{this.name}}>{{this.title}}</label>
|
||||||
|
<HouseAdsChooser
|
||||||
|
@settingValue={{this.adValue}}
|
||||||
|
@choices={{this.adNames}}
|
||||||
|
@onChange={{this.changeAdValue}}
|
||||||
|
/>
|
||||||
|
<div class="setting-controls">
|
||||||
|
{{#if this.changed}}
|
||||||
|
<DButton class="ok" @action={{action "save"}} @icon="check" />
|
||||||
|
<DButton class="cancel" @action={{action "cancel"}} @icon="xmark" />
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<p class="help">{{this.help}}</p>
|
||||||
|
</template>
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import Component from "@ember/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { classNames } from "@ember-decorators/component";
|
||||||
|
import DButton from "discourse/components/d-button";
|
||||||
|
import TextField from "discourse/components/text-field";
|
||||||
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
import { i18n as computedI18n, propertyNotEqual } from "discourse/lib/computed";
|
||||||
|
import { i18n } from "discourse-i18n";
|
||||||
|
|
||||||
|
@classNames("house-ads-setting")
|
||||||
|
export default class HouseAdsSetting extends Component {
|
||||||
|
adValue = "";
|
||||||
|
saving = false;
|
||||||
|
savingStatus = "";
|
||||||
|
|
||||||
|
@computedI18n("name", "admin.adplugin.house_ads.%@.title") title;
|
||||||
|
@computedI18n("name", "admin.adplugin.house_ads.%@.description") help;
|
||||||
|
@propertyNotEqual("adValue", "value") changed;
|
||||||
|
|
||||||
|
init() {
|
||||||
|
super.init(...arguments);
|
||||||
|
this.set("adValue", this.get("value"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
save() {
|
||||||
|
if (!this.get("saving")) {
|
||||||
|
this.setProperties({
|
||||||
|
saving: true,
|
||||||
|
savingStatus: i18n("saving"),
|
||||||
|
});
|
||||||
|
|
||||||
|
ajax(`/admin/plugins/pluginad/house_settings/${this.get("name")}.json`, {
|
||||||
|
type: "PUT",
|
||||||
|
data: { value: this.get("adValue") },
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
const adSettings = this.get("adSettings");
|
||||||
|
adSettings.set(this.get("name"), this.get("adValue"));
|
||||||
|
this.setProperties({
|
||||||
|
value: this.get("adValue"),
|
||||||
|
savingStatus: i18n("saved"),
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(popupAjaxError)
|
||||||
|
.finally(() => {
|
||||||
|
this.setProperties({
|
||||||
|
saving: false,
|
||||||
|
savingStatus: "",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
cancel() {
|
||||||
|
this.set("adValue", this.get("value"));
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<label for={{this.name}}>{{this.title}}</label>
|
||||||
|
<TextField @value={{this.adValue}} @classNames="house-ads-text-input" />
|
||||||
|
<div class="setting-controls">
|
||||||
|
{{#if this.changed}}
|
||||||
|
<DButton class="ok" @action={{action "save"}} @icon="check" />
|
||||||
|
<DButton class="cancel" @action={{action "cancel"}} @icon="xmark" />
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<p class="help">{{this.help}}</p>
|
||||||
|
</template>
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { htmlSafe } from "@ember/template";
|
||||||
|
import DModal from "discourse/components/d-modal";
|
||||||
|
import { i18n } from "discourse-i18n";
|
||||||
|
|
||||||
|
const Preview = <template>
|
||||||
|
<DModal
|
||||||
|
@closeModal={{@closeModal}}
|
||||||
|
@title={{i18n "admin.adplugin.house_ads.preview"}}
|
||||||
|
>
|
||||||
|
<:body>
|
||||||
|
<div class="house-ad-preview">
|
||||||
|
{{htmlSafe @model.html}}
|
||||||
|
</div>
|
||||||
|
</:body>
|
||||||
|
</DModal>
|
||||||
|
</template>;
|
||||||
|
|
||||||
|
export default Preview;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
|
import { alias } from "@ember/object/computed";
|
||||||
|
|
||||||
|
export default class AdminPluginsHouseAdsIndexController extends Controller {
|
||||||
|
@controller("adminPlugins.houseAds") adminPluginsHouseAds;
|
||||||
|
|
||||||
|
@alias("adminPluginsHouseAds.model") houseAds;
|
||||||
|
@alias("adminPluginsHouseAds.houseAdsSettings") adSettings;
|
||||||
|
}
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
|
import EmberObject, { action } from "@ember/object";
|
||||||
|
import { service } from "@ember/service";
|
||||||
|
import { TrackedObject } from "@ember-compat/tracked-built-ins";
|
||||||
|
import { observes } from "@ember-decorators/object";
|
||||||
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
import Category from "discourse/models/category";
|
||||||
|
import { i18n } from "discourse-i18n";
|
||||||
|
import Preview from "../components/modal/preview";
|
||||||
|
|
||||||
|
export default class adminPluginsHouseAdsShow extends Controller {
|
||||||
|
@service router;
|
||||||
|
@service modal;
|
||||||
|
|
||||||
|
@controller("adminPlugins.houseAds") houseAdsController;
|
||||||
|
|
||||||
|
@tracked selectedCategories = [];
|
||||||
|
@tracked selectedGroups = [];
|
||||||
|
@tracked saving = false;
|
||||||
|
@tracked savingStatus = "";
|
||||||
|
@tracked buffered;
|
||||||
|
|
||||||
|
@observes("model")
|
||||||
|
modelChanged() {
|
||||||
|
this.buffered = new TrackedObject({ ...this.model });
|
||||||
|
this.selectedCategories = this.model.categories || [];
|
||||||
|
this.selectedGroups = this.model.group_ids || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
get disabledSave() {
|
||||||
|
for (const key in this.buffered) {
|
||||||
|
// we don't want to compare the categories array
|
||||||
|
if (key !== "categories" && this.buffered[key] !== this.model[key]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
async save() {
|
||||||
|
if (!this.saving) {
|
||||||
|
this.saving = true;
|
||||||
|
this.savingStatus = i18n("saving");
|
||||||
|
const data = {};
|
||||||
|
const newRecord = !this.buffered.id;
|
||||||
|
if (!newRecord) {
|
||||||
|
data.id = this.buffered.id;
|
||||||
|
}
|
||||||
|
data.name = this.buffered.name;
|
||||||
|
data.html = this.buffered.html;
|
||||||
|
data.visible_to_logged_in_users =
|
||||||
|
this.buffered.visible_to_logged_in_users;
|
||||||
|
data.visible_to_anons = this.buffered.visible_to_anons;
|
||||||
|
data.category_ids = this.buffered.category_ids;
|
||||||
|
data.group_ids = this.buffered.group_ids;
|
||||||
|
try {
|
||||||
|
const ajaxData = await ajax(
|
||||||
|
newRecord
|
||||||
|
? `/admin/plugins/pluginad/house_creatives`
|
||||||
|
: `/admin/plugins/pluginad/house_creatives/${this.buffered.id}`,
|
||||||
|
{
|
||||||
|
type: newRecord ? "POST" : "PUT",
|
||||||
|
data,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.savingStatus = i18n("saved");
|
||||||
|
const houseAds = this.houseAdsController.model;
|
||||||
|
if (newRecord) {
|
||||||
|
this.buffered.id = ajaxData.house_ad.id;
|
||||||
|
if (!houseAds.includes(this.buffered)) {
|
||||||
|
houseAds.pushObject(EmberObject.create(this.buffered));
|
||||||
|
}
|
||||||
|
this.router.transitionTo(
|
||||||
|
"adminPlugins.houseAds.show",
|
||||||
|
this.buffered.id
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
houseAds
|
||||||
|
.find((ad) => ad.id === this.buffered.id)
|
||||||
|
.setProperties(this.buffered);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
popupAjaxError(error);
|
||||||
|
} finally {
|
||||||
|
this.set("model", this.buffered);
|
||||||
|
this.saving = false;
|
||||||
|
this.savingStatus = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
setCategoryIds(categoryArray) {
|
||||||
|
this.selectedCategories = categoryArray;
|
||||||
|
this.buffered.category_ids = categoryArray.map((c) => c.id);
|
||||||
|
this.setCategoriesForBuffered();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
setGroupIds(groupIds) {
|
||||||
|
this.selectedGroups = groupIds;
|
||||||
|
this.buffered.group_ids = groupIds.map((id) => id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
cancel() {
|
||||||
|
this.buffered = new TrackedObject({ ...this.model });
|
||||||
|
this.selectedCategories = this.model.categories || [];
|
||||||
|
this.selectedGroups = this.model.group_ids || [];
|
||||||
|
this.setCategoriesForBuffered();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
async destroy() {
|
||||||
|
if (!this.buffered.id) {
|
||||||
|
this.router.transitionTo("adminPlugins.houseAds.index");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await ajax(
|
||||||
|
`/admin/plugins/pluginad/house_creatives/${this.buffered.id}`,
|
||||||
|
{
|
||||||
|
type: "DELETE",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.houseAdsController.model.removeObject(
|
||||||
|
this.houseAdsController.model.findBy("id", this.buffered.id)
|
||||||
|
);
|
||||||
|
this.router.transitionTo("adminPlugins.houseAds.index");
|
||||||
|
} catch (error) {
|
||||||
|
popupAjaxError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
openPreview() {
|
||||||
|
this.modal.show(Preview, {
|
||||||
|
model: {
|
||||||
|
html: this.buffered.html,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setCategoriesForBuffered() {
|
||||||
|
// we need to fetch the categories because the serializer is not being used
|
||||||
|
// to attach the category object to the house ads
|
||||||
|
this.buffered.categories = this.buffered.category_ids
|
||||||
|
? this.buffered.category_ids.map((categoryId) =>
|
||||||
|
Category.findById(categoryId)
|
||||||
|
)
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import Controller from "@ember/controller";
|
||||||
|
|
||||||
|
export default class AdminPluginsHouseAdsController extends Controller {
|
||||||
|
loadingAds = true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
|
import { service } from "@ember/service";
|
||||||
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
|
||||||
|
export default class AdminPluginsHouseAdsIndex extends DiscourseRoute {
|
||||||
|
@service router;
|
||||||
|
|
||||||
|
@action
|
||||||
|
moreSettings() {
|
||||||
|
this.router.transitionTo("adminSiteSettingsCategory", "ad_plugin");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { TrackedObject } from "@ember-compat/tracked-built-ins";
|
||||||
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
import { i18n } from "discourse-i18n";
|
||||||
|
|
||||||
|
export default class AdminPluginsHouseAdsShow extends DiscourseRoute {
|
||||||
|
model(params) {
|
||||||
|
if (params.ad_id === "new") {
|
||||||
|
return new TrackedObject({
|
||||||
|
name: i18n("admin.adplugin.house_ads.new_name"),
|
||||||
|
html: "",
|
||||||
|
visible_to_logged_in_users: true,
|
||||||
|
visible_to_anons: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new TrackedObject(
|
||||||
|
this.modelFor("adminPlugins.houseAds").findBy(
|
||||||
|
"id",
|
||||||
|
parseInt(params.ad_id, 10)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-5
@@ -2,15 +2,15 @@ import EmberObject from "@ember/object";
|
|||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import DiscourseRoute from "discourse/routes/discourse";
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
|
||||||
export default DiscourseRoute.extend({
|
export default class AdminPluginsHouseAds extends DiscourseRoute {
|
||||||
settings: null,
|
settings = null;
|
||||||
|
|
||||||
model() {
|
model() {
|
||||||
return ajax("/admin/plugins/pluginad/house_creatives.json").then((data) => {
|
return ajax("/admin/plugins/pluginad/house_creatives.json").then((data) => {
|
||||||
this.set("settings", EmberObject.create(data.settings));
|
this.set("settings", EmberObject.create(data.settings));
|
||||||
return data.house_ads.map((ad) => EmberObject.create(ad));
|
return data.house_ads.map((ad) => EmberObject.create(ad));
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
setupController(controller, model) {
|
setupController(controller, model) {
|
||||||
controller.setProperties({
|
controller.setProperties({
|
||||||
@@ -18,5 +18,5 @@ export default DiscourseRoute.extend({
|
|||||||
houseAdsSettings: this.get("settings"),
|
houseAdsSettings: this.get("settings"),
|
||||||
loadingAds: false,
|
loadingAds: false,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import { LinkTo } from "@ember/routing";
|
||||||
|
import RouteTemplate from "ember-route-template";
|
||||||
|
import DButton from "discourse/components/d-button";
|
||||||
|
import routeAction from "discourse/helpers/route-action";
|
||||||
|
import { i18n } from "discourse-i18n";
|
||||||
|
import HouseAdsListSetting from "../components/house-ads-list-setting";
|
||||||
|
|
||||||
|
export default RouteTemplate(
|
||||||
|
<template>
|
||||||
|
<section class="house-ads-settings content-body">
|
||||||
|
<div>{{i18n "admin.adplugin.house_ads.description"}}</div>
|
||||||
|
|
||||||
|
{{#if @controller.houseAds.length}}
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<HouseAdsListSetting
|
||||||
|
@name="topic_list_top"
|
||||||
|
@value={{@controller.adSettings.topic_list_top}}
|
||||||
|
@allAds={{@controller.houseAds}}
|
||||||
|
@adSettings={{@controller.adSettings}}
|
||||||
|
/>
|
||||||
|
<HouseAdsListSetting
|
||||||
|
@name="topic_above_post_stream"
|
||||||
|
@value={{@controller.adSettings.topic_above_post_stream}}
|
||||||
|
@allAds={{@controller.houseAds}}
|
||||||
|
@adSettings={{@controller.adSettings}}
|
||||||
|
/>
|
||||||
|
<HouseAdsListSetting
|
||||||
|
@name="topic_above_suggested"
|
||||||
|
@value={{@controller.adSettings.topic_above_suggested}}
|
||||||
|
@allAds={{@controller.houseAds}}
|
||||||
|
@adSettings={{@controller.adSettings}}
|
||||||
|
/>
|
||||||
|
<HouseAdsListSetting
|
||||||
|
@name="post_bottom"
|
||||||
|
@value={{@controller.adSettings.post_bottom}}
|
||||||
|
@allAds={{@controller.houseAds}}
|
||||||
|
@adSettings={{@controller.adSettings}}
|
||||||
|
/>
|
||||||
|
<HouseAdsListSetting
|
||||||
|
@name="topic_list_between"
|
||||||
|
@value={{@controller.adSettings.topic_list_between}}
|
||||||
|
@allAds={{@controller.houseAds}}
|
||||||
|
@adSettings={{@controller.adSettings}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<DButton
|
||||||
|
@label="admin.adplugin.house_ads.more_settings"
|
||||||
|
@icon="gear"
|
||||||
|
@action={{routeAction "moreSettings"}}
|
||||||
|
class="btn-default"
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
{{else}}
|
||||||
|
<p>
|
||||||
|
{{#LinkTo route="adminPlugins.houseAds.show" model="new"}}
|
||||||
|
{{i18n "admin.adplugin.house_ads.get_started"}}
|
||||||
|
{{/LinkTo}}
|
||||||
|
</p>
|
||||||
|
{{/if}}
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
);
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import { Input } from "@ember/component";
|
||||||
|
import { fn, hash } from "@ember/helper";
|
||||||
|
import RouteTemplate from "ember-route-template";
|
||||||
|
import AceEditor from "discourse/components/ace-editor";
|
||||||
|
import DButton from "discourse/components/d-button";
|
||||||
|
import TextField from "discourse/components/text-field";
|
||||||
|
import { i18n } from "discourse-i18n";
|
||||||
|
import GroupChooser from "select-kit/components/group-chooser";
|
||||||
|
import HouseAdsCategorySelector from "../components/house-ads-category-selector";
|
||||||
|
|
||||||
|
export default RouteTemplate(
|
||||||
|
<template>
|
||||||
|
<section class="edit-house-ad content-body">
|
||||||
|
<h1><TextField
|
||||||
|
@value={{@controller.buffered.name}}
|
||||||
|
class="house-ad-name"
|
||||||
|
/></h1>
|
||||||
|
<div class="controls">
|
||||||
|
<AceEditor
|
||||||
|
@content={{@controller.buffered.html}}
|
||||||
|
@onChange={{fn (mut @controller.buffered.html)}}
|
||||||
|
@mode="html"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<div class="visibility-settings">
|
||||||
|
<div>
|
||||||
|
<Input
|
||||||
|
@type="checkbox"
|
||||||
|
@checked={{@controller.buffered.visible_to_logged_in_users}}
|
||||||
|
class="visible-to-logged-in-checkbox"
|
||||||
|
/>
|
||||||
|
<span>{{i18n
|
||||||
|
"admin.adplugin.house_ads.show_to_logged_in_users"
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Input
|
||||||
|
class="visible-to-anonymous-checkbox"
|
||||||
|
@type="checkbox"
|
||||||
|
@checked={{@controller.buffered.visible_to_anons}}
|
||||||
|
/>
|
||||||
|
<span>{{i18n "admin.adplugin.house_ads.show_to_anons"}}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<HouseAdsCategorySelector
|
||||||
|
@categories={{@controller.site.categories}}
|
||||||
|
@selectedCategories={{@controller.selectedCategories}}
|
||||||
|
@onChange={{@controller.setCategoryIds}}
|
||||||
|
@options={{hash allowAny=true}}
|
||||||
|
class="house-ads-categories"
|
||||||
|
/>
|
||||||
|
<div class="description">
|
||||||
|
{{i18n "admin.adplugin.house_ads.category_chooser_description"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<GroupChooser
|
||||||
|
@content={{@controller.site.groups}}
|
||||||
|
@onChange={{@controller.setGroupIds}}
|
||||||
|
@value={{@controller.selectedGroups}}
|
||||||
|
class="banner-groups"
|
||||||
|
/>
|
||||||
|
<div class="description">
|
||||||
|
{{i18n "admin.adplugin.house_ads.group_chooser_description"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DButton
|
||||||
|
@action={{@controller.save}}
|
||||||
|
@disabled={{@controller.disabledSave}}
|
||||||
|
@label="admin.adplugin.house_ads.save"
|
||||||
|
class="btn-primary save-button"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{{#if @controller.saving}}
|
||||||
|
{{@controller.savingStatus}}
|
||||||
|
{{else}}
|
||||||
|
{{#unless @controller.disabledSave}}
|
||||||
|
<DButton @action={{@controller.cancel}} @label="cancel" />
|
||||||
|
{{/unless}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<DButton
|
||||||
|
@action={{@controller.openPreview}}
|
||||||
|
@label="admin.adplugin.house_ads.preview"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<DButton
|
||||||
|
@action={{@controller.destroy}}
|
||||||
|
@label="admin.adplugin.house_ads.delete"
|
||||||
|
class="btn-danger delete-button"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
);
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { LinkTo } from "@ember/routing";
|
||||||
|
import RouteTemplate from "ember-route-template";
|
||||||
|
import icon from "discourse/helpers/d-icon";
|
||||||
|
import { i18n } from "discourse-i18n";
|
||||||
|
|
||||||
|
export default RouteTemplate(
|
||||||
|
<template>
|
||||||
|
<div class="adplugin-mgmt">
|
||||||
|
<h1>{{i18n "admin.adplugin.house_ads.title"}}</h1>
|
||||||
|
{{#if @controller.model.length}}
|
||||||
|
<div class="content-list">
|
||||||
|
<div class="house-ads-actions">
|
||||||
|
<LinkTo
|
||||||
|
@route="adminPlugins.houseAds.show"
|
||||||
|
@model="new"
|
||||||
|
class="btn btn-primary"
|
||||||
|
>
|
||||||
|
{{icon "plus"}}
|
||||||
|
<span>{{i18n "admin.adplugin.house_ads.new"}}</span>
|
||||||
|
</LinkTo>
|
||||||
|
<LinkTo
|
||||||
|
@route="adminPlugins.houseAds.index"
|
||||||
|
class="btn btn-default"
|
||||||
|
>
|
||||||
|
{{icon "gear"}}
|
||||||
|
<span>{{i18n "admin.adplugin.house_ads.settings"}}</span>
|
||||||
|
</LinkTo>
|
||||||
|
</div>
|
||||||
|
<ul class="house-ads-list">
|
||||||
|
{{#each @controller.model as |ad|}}
|
||||||
|
<li class="house-ads-list-item">
|
||||||
|
{{#LinkTo route="adminPlugins.houseAds.show" model=ad.id}}
|
||||||
|
{{ad.name}}
|
||||||
|
{{/LinkTo}}
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{outlet}}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
);
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
#
|
||||||
|
class AdstxtController < ::ApplicationController
|
||||||
|
requires_plugin AdPlugin.plugin_name
|
||||||
|
|
||||||
|
skip_before_action :preload_json, :check_xhr, :redirect_to_login_if_required
|
||||||
|
|
||||||
|
def index
|
||||||
|
raise Discourse::NotFound if SiteSetting.ads_txt.blank?
|
||||||
|
|
||||||
|
render plain: SiteSetting.ads_txt
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -5,11 +5,23 @@ module ::AdPlugin
|
|||||||
requires_plugin AdPlugin.plugin_name
|
requires_plugin AdPlugin.plugin_name
|
||||||
|
|
||||||
def index
|
def index
|
||||||
render_json_dump(house_ads: HouseAd.all.map(&:to_hash), settings: HouseAdSetting.all)
|
render_json_dump(
|
||||||
|
house_ads:
|
||||||
|
HouseAd.all.map do |ad|
|
||||||
|
ad.to_hash.merge!(categories: Category.secured(@guardian).where(id: ad.category_ids))
|
||||||
|
end,
|
||||||
|
settings: HouseAdSetting.all,
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
render_json_dump(house_ad: HouseAd.find(params[:id])&.to_hash)
|
house_ad_hash = HouseAd.find(params[:id])&.to_hash
|
||||||
|
if house_ad_hash
|
||||||
|
house_ad_hash.merge!(
|
||||||
|
categories: Category.secured(@guardian).where(id: house_ad_hash[:category_ids]),
|
||||||
|
)
|
||||||
|
end
|
||||||
|
render_json_dump(house_ad: house_ad_hash)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@@ -41,7 +53,15 @@ module ::AdPlugin
|
|||||||
@permitted ||=
|
@permitted ||=
|
||||||
begin
|
begin
|
||||||
permitted =
|
permitted =
|
||||||
params.permit(:id, :name, :html, :visible_to_anons, :visible_to_logged_in_users)
|
params.permit(
|
||||||
|
:id,
|
||||||
|
:name,
|
||||||
|
:html,
|
||||||
|
:visible_to_anons,
|
||||||
|
:visible_to_logged_in_users,
|
||||||
|
group_ids: [],
|
||||||
|
category_ids: [],
|
||||||
|
)
|
||||||
permitted[:visible_to_logged_in_users] = ActiveModel::Type::Boolean.new.cast(
|
permitted[:visible_to_logged_in_users] = ActiveModel::Type::Boolean.new.cast(
|
||||||
permitted[:visible_to_logged_in_users],
|
permitted[:visible_to_logged_in_users],
|
||||||
)
|
)
|
||||||
|
|||||||
+40
-9
@@ -4,7 +4,13 @@ module ::AdPlugin
|
|||||||
class HouseAd
|
class HouseAd
|
||||||
include ActiveModel::Validations
|
include ActiveModel::Validations
|
||||||
|
|
||||||
attr_accessor :id, :name, :html, :visible_to_logged_in_users, :visible_to_anons
|
attr_accessor :id,
|
||||||
|
:name,
|
||||||
|
:html,
|
||||||
|
:visible_to_logged_in_users,
|
||||||
|
:visible_to_anons,
|
||||||
|
:category_ids,
|
||||||
|
:group_ids
|
||||||
|
|
||||||
NAME_REGEX = /\A[[:alnum:]\s\.,'!@#$%&\*\-\+\=:]*\z/i
|
NAME_REGEX = /\A[[:alnum:]\s\.,'!@#$%&\*\-\+\=:]*\z/i
|
||||||
|
|
||||||
@@ -22,6 +28,8 @@ module ::AdPlugin
|
|||||||
@html = "<div class='house-ad'>New Ad</div>"
|
@html = "<div class='house-ad'>New Ad</div>"
|
||||||
@visible_to_logged_in_users = true
|
@visible_to_logged_in_users = true
|
||||||
@visible_to_anons = true
|
@visible_to_anons = true
|
||||||
|
@group_ids = []
|
||||||
|
@category_ids = []
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.from_hash(h)
|
def self.from_hash(h)
|
||||||
@@ -29,10 +37,12 @@ module ::AdPlugin
|
|||||||
ad.name = h[:name]
|
ad.name = h[:name]
|
||||||
ad.html = h[:html]
|
ad.html = h[:html]
|
||||||
ad.id = h[:id].to_i if h[:id]
|
ad.id = h[:id].to_i if h[:id]
|
||||||
if h.key?(:visible_to_logged_in_users)
|
ad.visible_to_logged_in_users = h[:visible_to_logged_in_users] if h.key?(
|
||||||
ad.visible_to_logged_in_users = h[:visible_to_logged_in_users]
|
:visible_to_logged_in_users,
|
||||||
end
|
)
|
||||||
ad.visible_to_anons = h[:visible_to_anons] if h.key?(:visible_to_anons)
|
ad.visible_to_anons = h[:visible_to_anons] if h.key?(:visible_to_anons)
|
||||||
|
ad.group_ids = h[:group_ids].map(&:to_i) if h.key?(:group_ids)
|
||||||
|
ad.category_ids = h[:category_ids].map(&:to_i) if h.key?(:category_ids)
|
||||||
ad
|
ad
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -72,8 +82,24 @@ module ::AdPlugin
|
|||||||
self.all.select(&:visible_to_anons)
|
self.all.select(&:visible_to_anons)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.all_for_logged_in_users
|
def self.all_for_logged_in_users(scope)
|
||||||
self.all.select(&:visible_to_logged_in_users)
|
if scope.nil?
|
||||||
|
# this is for our admin page, so we don't need to filter by group
|
||||||
|
self.all.select(&:visible_to_logged_in_users)
|
||||||
|
else
|
||||||
|
# otherwise, filter by group and visible categories
|
||||||
|
self.all.select do |ad|
|
||||||
|
(
|
||||||
|
ad.group_ids.any? { |group_id| scope.user.groups.pluck(:id).include?(group_id) } ||
|
||||||
|
ad.group_ids.include?(Group::AUTO_GROUPS[:everyone]) || ad.group_ids.empty?
|
||||||
|
) && ad.visible_to_logged_in_users &&
|
||||||
|
(
|
||||||
|
ad.category_ids.any? do |category_id|
|
||||||
|
Category.secured(scope).pluck(:id).include?(category_id)
|
||||||
|
end || true
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def save
|
def save
|
||||||
@@ -91,10 +117,13 @@ module ::AdPlugin
|
|||||||
def update(attrs)
|
def update(attrs)
|
||||||
self.name = attrs[:name]
|
self.name = attrs[:name]
|
||||||
self.html = attrs[:html]
|
self.html = attrs[:html]
|
||||||
if attrs.key?(:visible_to_logged_in_users)
|
self.visible_to_logged_in_users = attrs[:visible_to_logged_in_users] if attrs.key?(
|
||||||
self.visible_to_logged_in_users = attrs[:visible_to_logged_in_users]
|
:visible_to_logged_in_users,
|
||||||
end
|
)
|
||||||
self.visible_to_anons = attrs[:visible_to_anons] if attrs.key?(:visible_to_anons)
|
self.visible_to_anons = attrs[:visible_to_anons] if attrs.key?(:visible_to_anons)
|
||||||
|
# ensure that group_ids and category_ids can be set to an empty array
|
||||||
|
self.group_ids = attrs.key?(:group_ids) ? attrs[:group_ids].map(&:to_i) : []
|
||||||
|
self.category_ids = attrs.key?(:category_ids) ? attrs[:category_ids].map(&:to_i) : []
|
||||||
self.save
|
self.save
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -105,6 +134,8 @@ module ::AdPlugin
|
|||||||
html: @html,
|
html: @html,
|
||||||
visible_to_logged_in_users: @visible_to_logged_in_users,
|
visible_to_logged_in_users: @visible_to_logged_in_users,
|
||||||
visible_to_anons: @visible_to_anons,
|
visible_to_anons: @visible_to_anons,
|
||||||
|
group_ids: @group_ids,
|
||||||
|
category_ids: @category_ids,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -21,14 +21,14 @@ module ::AdPlugin
|
|||||||
settings
|
settings
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.settings_and_ads(for_anons: true)
|
def self.settings_and_ads(for_anons: true, scope: nil)
|
||||||
settings = AdPlugin::HouseAdSetting.all
|
settings = AdPlugin::HouseAdSetting.all
|
||||||
ad_names = settings.values.map { |v| v.split("|") }.flatten.uniq
|
ad_names = settings.values.map { |v| v.split("|") }.flatten.uniq
|
||||||
|
|
||||||
if for_anons
|
if for_anons
|
||||||
ads = AdPlugin::HouseAd.all_for_anons
|
ads = AdPlugin::HouseAd.all_for_anons
|
||||||
else
|
else
|
||||||
ads = AdPlugin::HouseAd.all_for_logged_in_users
|
ads = AdPlugin::HouseAd.all_for_logged_in_users(scope)
|
||||||
end
|
end
|
||||||
ads = ads.select { |ad| ad_names.include?(ad.name) }
|
ads = ads.select { |ad| ad_names.include?(ad.name) }
|
||||||
|
|
||||||
@@ -41,14 +41,14 @@ module ::AdPlugin
|
|||||||
),
|
),
|
||||||
creatives:
|
creatives:
|
||||||
ads.inject({}) do |h, ad|
|
ads.inject({}) do |h, ad|
|
||||||
h[ad.name] = ad.html
|
h[ad.name] = { html: ad.html, category_ids: ad.category_ids }
|
||||||
h
|
h
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.update(setting_name, value)
|
def self.update(setting_name, value)
|
||||||
raise Discourse::NotFound unless DEFAULTS.keys.include?(setting_name.to_sym)
|
raise Discourse::NotFound if DEFAULTS.keys.exclude?(setting_name.to_sym)
|
||||||
|
|
||||||
ad_names = value&.split("|") || []
|
ad_names = value&.split("|") || []
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +1,36 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { alias, or } from "@ember/object/computed";
|
import { alias, or } from "@ember/object/computed";
|
||||||
import { inject as service } from "@ember/service";
|
import { service } from "@ember/service";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse/lib/decorators";
|
||||||
import {
|
import {
|
||||||
isNthPost,
|
isNthPost,
|
||||||
isNthTopicListItem,
|
isNthTopicListItem,
|
||||||
} from "discourse/plugins/discourse-adplugin/discourse/helpers/slot-position";
|
} from "discourse/plugins/discourse-adplugin/discourse/helpers/slot-position";
|
||||||
|
|
||||||
export default Component.extend({
|
export default class AdComponent extends Component {
|
||||||
router: service(),
|
@service router;
|
||||||
|
|
||||||
currentCategoryId: or(
|
@or(
|
||||||
"router.currentRoute.attributes.category.id",
|
"router.currentRoute.attributes.category.id",
|
||||||
"router.currentRoute.parent.attributes.category_id"
|
"router.currentRoute.parent.attributes.category_id"
|
||||||
),
|
)
|
||||||
|
currentCategoryId;
|
||||||
|
|
||||||
currentCategorySlug: or(
|
@or(
|
||||||
"router.currentRoute.attributes.category.slug",
|
"router.currentRoute.attributes.category.slug",
|
||||||
"router.currentRoute.parent.attributes.category.slug"
|
"router.currentRoute.parent.attributes.category.slug"
|
||||||
),
|
)
|
||||||
|
currentCategorySlug;
|
||||||
|
|
||||||
// Server needs to compute this in case hidden tags are being used.
|
// Server needs to compute this in case hidden tags are being used.
|
||||||
topicTagsDisableAds: alias(
|
@alias("router.currentRoute.parent.attributes.tags_disable_ads")
|
||||||
"router.currentRoute.parent.attributes.tags_disable_ads"
|
topicTagsDisableAds;
|
||||||
),
|
|
||||||
|
|
||||||
isRestrictedCategory: or(
|
@or(
|
||||||
"router.currentRoute.attributes.category.read_restricted",
|
"router.currentRoute.attributes.category.read_restricted",
|
||||||
"router.currentRoute.parent.attributes.category.read_restricted"
|
"router.currentRoute.parent.attributes.category.read_restricted"
|
||||||
),
|
)
|
||||||
|
isRestrictedCategory;
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"router.currentRoute.attributes.__type",
|
"router.currentRoute.attributes.__type",
|
||||||
@@ -38,33 +40,21 @@ export default Component.extend({
|
|||||||
if (type === "tag" && tag) {
|
if (type === "tag" && tag) {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("router.currentRoute.parent.attributes.archetype")
|
@discourseComputed("router.currentRoute.parent.attributes.archetype")
|
||||||
isPersonalMessage(topicType) {
|
isPersonalMessage(topicType) {
|
||||||
return topicType === "private_message";
|
return topicType === "private_message";
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("currentUser.groups")
|
@discourseComputed
|
||||||
showToGroups(groups) {
|
showToGroups() {
|
||||||
const currentUser = this.currentUser;
|
if (!this.currentUser) {
|
||||||
|
|
||||||
if (
|
|
||||||
!currentUser ||
|
|
||||||
!groups ||
|
|
||||||
!this.siteSettings.no_ads_for_groups ||
|
|
||||||
this.siteSettings.no_ads_for_groups.length === 0
|
|
||||||
) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let noAdsGroups = this.siteSettings.no_ads_for_groups
|
return this.currentUser.show_to_groups;
|
||||||
.split("|")
|
}
|
||||||
.filter(Boolean);
|
|
||||||
let currentGroups = groups.map((g) => g.id.toString());
|
|
||||||
|
|
||||||
return !currentGroups.any((g) => noAdsGroups.includes(g));
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"currentCategoryId",
|
"currentCategoryId",
|
||||||
@@ -94,13 +84,13 @@ export default Component.extend({
|
|||||||
(!isRestrictedCategory ||
|
(!isRestrictedCategory ||
|
||||||
!this.siteSettings.no_ads_for_restricted_categories)
|
!this.siteSettings.no_ads_for_restricted_categories)
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
isNthPost(n) {
|
isNthPost(n) {
|
||||||
return isNthPost(n, this.get("postNumber"));
|
return isNthPost(n, this.get("postNumber"));
|
||||||
},
|
}
|
||||||
|
|
||||||
isNthTopicListItem(n) {
|
isNthTopicListItem(n) {
|
||||||
return isNthTopicListItem(n, this.get("indexNumber"));
|
return isNthTopicListItem(n, this.get("indexNumber"));
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
+50
-29
@@ -1,11 +1,26 @@
|
|||||||
|
import { array } from "@ember/helper";
|
||||||
import EmberObject from "@ember/object";
|
import EmberObject from "@ember/object";
|
||||||
|
import { service } from "@ember/service";
|
||||||
import { isBlank } from "@ember/utils";
|
import { isBlank } from "@ember/utils";
|
||||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
import { tagName } from "@ember-decorators/component";
|
||||||
import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad-component";
|
import discourseComputed from "discourse/lib/decorators";
|
||||||
import {
|
import { isNthPost, isNthTopicListItem } from "../helpers/slot-position";
|
||||||
isNthPost,
|
import AdComponent from "./ad-component";
|
||||||
isNthTopicListItem,
|
import AdbutlerAd from "./adbutler-ad";
|
||||||
} from "discourse/plugins/discourse-adplugin/discourse/helpers/slot-position";
|
import AmazonProductLinks from "./amazon-product-links";
|
||||||
|
import CarbonadsAd from "./carbonads-ad";
|
||||||
|
import GoogleAdsense from "./google-adsense";
|
||||||
|
import GoogleDfpAd from "./google-dfp-ad";
|
||||||
|
import HouseAd from "./house-ad";
|
||||||
|
|
||||||
|
const AD_COMPONENTS = {
|
||||||
|
"house-ad": HouseAd,
|
||||||
|
"google-adsense": GoogleAdsense,
|
||||||
|
"google-dfp-ad": GoogleDfpAd,
|
||||||
|
"amazon-product-links": AmazonProductLinks,
|
||||||
|
"carbonads-ad": CarbonadsAd,
|
||||||
|
"adbutler-ad": AdbutlerAd,
|
||||||
|
};
|
||||||
|
|
||||||
const adConfig = EmberObject.create({
|
const adConfig = EmberObject.create({
|
||||||
"google-adsense": {
|
"google-adsense": {
|
||||||
@@ -172,9 +187,9 @@ export function slotContenders(
|
|||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AdComponent.extend({
|
@tagName("")
|
||||||
needsUpdate: false,
|
export default class AdSlot extends AdComponent {
|
||||||
tagName: "",
|
@service router;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For a given ad placement and optionally a post number if in between posts,
|
* For a given ad placement and optionally a post number if in between posts,
|
||||||
@@ -189,30 +204,17 @@ export default AdComponent.extend({
|
|||||||
indexNumber,
|
indexNumber,
|
||||||
postNumber
|
postNumber
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* When house ads are configured to alternate with other ad networks, we
|
|
||||||
* need to trigger an update of which ad component is shown after
|
|
||||||
* navigating between topic lists or topics.
|
|
||||||
*/
|
|
||||||
@observes("refreshOnChange")
|
|
||||||
changed() {
|
|
||||||
if (this.get("listLoading")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// force adComponents to be recomputed
|
|
||||||
this.notifyPropertyChange("needsUpdate");
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of the names of ad components that should be rendered
|
* Returns a list of the names of ad components that should be rendered
|
||||||
* in the given ad placement. It handles alternating between house ads
|
* in the given ad placement. It handles alternating between house ads
|
||||||
* and other ad networks.
|
* and other ad networks.
|
||||||
|
*
|
||||||
|
* Depends on `router.currentRoute` so that we refresh ads when navigating around.
|
||||||
*/
|
*/
|
||||||
@discourseComputed("placement", "availableAdTypes", "needsUpdate")
|
@discourseComputed("placement", "availableAdTypes", "router.currentRoute")
|
||||||
adComponents(placement, availableAdTypes) {
|
adComponentNames(placement, availableAdTypes) {
|
||||||
if (
|
if (
|
||||||
!availableAdTypes.includes("house-ad") ||
|
!availableAdTypes.includes("house-ad") ||
|
||||||
availableAdTypes.length === 1
|
availableAdTypes.length === 1
|
||||||
@@ -250,5 +252,24 @@ export default AdComponent.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return networkNames;
|
return networkNames;
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
get adComponents() {
|
||||||
|
return this.adComponentNames.map((name) => AD_COMPONENTS[name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#each this.adComponents as |Ad|}}
|
||||||
|
{{! Trick to force full destroy/re-render of component when route changes }}
|
||||||
|
{{#each (array this.router.currentRoute)}}
|
||||||
|
<Ad
|
||||||
|
@placement={{this.placement}}
|
||||||
|
@category={{this.category}}
|
||||||
|
@postNumber={{this.postNumber}}
|
||||||
|
@indexNumber={{this.indexNumber}}
|
||||||
|
@tagName={{this.childTagName}}
|
||||||
|
/>
|
||||||
|
{{/each}}
|
||||||
|
{{/each}}
|
||||||
|
</template>
|
||||||
|
}
|
||||||
+29
-31
@@ -1,9 +1,9 @@
|
|||||||
import { scheduleOnce } from "@ember/runloop";
|
import { scheduleOnce } from "@ember/runloop";
|
||||||
import RSVP from "rsvp";
|
import RSVP from "rsvp";
|
||||||
|
import discourseComputed from "discourse/lib/decorators";
|
||||||
|
import { isTesting } from "discourse/lib/environment";
|
||||||
import loadScript from "discourse/lib/load-script";
|
import loadScript from "discourse/lib/load-script";
|
||||||
import { isTesting } from "discourse-common/config/environment";
|
import AdComponent from "./ad-component";
|
||||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
|
||||||
import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad-component";
|
|
||||||
|
|
||||||
let _loaded = false,
|
let _loaded = false,
|
||||||
_promise = null,
|
_promise = null,
|
||||||
@@ -27,9 +27,9 @@ function loadAdbutler(adserverHostname) {
|
|||||||
return _promise;
|
return _promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AdComponent.extend({
|
export default class AdbutlerAd extends AdComponent {
|
||||||
divs: null,
|
divs = null;
|
||||||
publisherId: null,
|
publisherId = null;
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
let dimensions = [728, 90];
|
let dimensions = [728, 90];
|
||||||
@@ -70,8 +70,8 @@ export default AdComponent.extend({
|
|||||||
dimensions,
|
dimensions,
|
||||||
});
|
});
|
||||||
|
|
||||||
this._super();
|
super.init();
|
||||||
},
|
}
|
||||||
|
|
||||||
_triggerAds() {
|
_triggerAds() {
|
||||||
if (isTesting()) {
|
if (isTesting()) {
|
||||||
@@ -104,52 +104,44 @@ export default AdComponent.extend({
|
|||||||
}
|
}
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this._super();
|
super.didInsertElement();
|
||||||
scheduleOnce("afterRender", this, this._triggerAds);
|
scheduleOnce("afterRender", this, this._triggerAds);
|
||||||
},
|
}
|
||||||
|
|
||||||
@observes("listLoading")
|
@discourseComputed
|
||||||
waitForLoad() {
|
showAdbutlerAds() {
|
||||||
if (this.get("adRequested")) {
|
if (!this.currentUser) {
|
||||||
return;
|
return true;
|
||||||
} // already requested that this ad unit be populated
|
|
||||||
if (!this.get("listLoading")) {
|
|
||||||
scheduleOnce("afterRender", this, this._triggerAds);
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed("currentUser.trust_level")
|
return this.currentUser.show_adbutler_ads;
|
||||||
showToTrustLevel(trustLevel) {
|
}
|
||||||
return !(
|
|
||||||
trustLevel && trustLevel > this.siteSettings.adbutler_through_trust_level
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"publisherId",
|
"publisherId",
|
||||||
"showToTrustLevel",
|
"showAdbutlerAds",
|
||||||
"showToGroups",
|
"showToGroups",
|
||||||
"showAfterPost",
|
"showAfterPost",
|
||||||
"showOnCurrentPage"
|
"showOnCurrentPage"
|
||||||
)
|
)
|
||||||
showAd(
|
showAd(
|
||||||
publisherId,
|
publisherId,
|
||||||
showToTrustLevel,
|
showAdbutlerAds,
|
||||||
showToGroups,
|
showToGroups,
|
||||||
showAfterPost,
|
showAfterPost,
|
||||||
showOnCurrentPage
|
showOnCurrentPage
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
publisherId &&
|
publisherId &&
|
||||||
showToTrustLevel &&
|
showAdbutlerAds &&
|
||||||
showToGroups &&
|
showToGroups &&
|
||||||
showAfterPost &&
|
showAfterPost &&
|
||||||
showOnCurrentPage
|
showOnCurrentPage
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("postNumber")
|
@discourseComputed("postNumber")
|
||||||
showAfterPost(postNumber) {
|
showAfterPost(postNumber) {
|
||||||
@@ -157,5 +149,11 @@ export default AdComponent.extend({
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return this.isNthPost(parseInt(this.siteSettings.adbutler_nth_post, 10));
|
return this.isNthPost(parseInt(this.siteSettings.adbutler_nth_post, 10));
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
<template>
|
||||||
|
{{#if this.showAd}}
|
||||||
|
<div id={{this.divId}} class={{this.className}}></div>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
||||||
+62
-26
@@ -1,17 +1,14 @@
|
|||||||
import { and } from "@ember/object/computed";
|
import { and } from "@ember/object/computed";
|
||||||
import { htmlSafe } from "@ember/template";
|
import { htmlSafe } from "@ember/template";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import { classNames } from "@ember-decorators/component";
|
||||||
import AdComponent from "discourse/plugins/discourse-adplugin/discourse/components/ad-component";
|
import discourseComputed from "discourse/lib/decorators";
|
||||||
|
import { i18n } from "discourse-i18n";
|
||||||
|
import AdComponent from "./ad-component";
|
||||||
|
|
||||||
export default AdComponent.extend({
|
@classNames("amazon-product-links")
|
||||||
classNames: ["amazon-product-links"],
|
export default class AmazonProductLinks extends AdComponent {
|
||||||
|
@and("showAmazonAds", "showToGroups", "showAfterPost", "showOnCurrentPage")
|
||||||
showAd: and(
|
showAd;
|
||||||
"showToTrustLevel",
|
|
||||||
"showToGroups",
|
|
||||||
"showAfterPost",
|
|
||||||
"showOnCurrentPage"
|
|
||||||
),
|
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
const data = {
|
const data = {
|
||||||
@@ -145,40 +142,42 @@ export default AdComponent.extend({
|
|||||||
this.set("user_input_mobile", data[placement]["user_input_mobile"]);
|
this.set("user_input_mobile", data[placement]["user_input_mobile"]);
|
||||||
this.set("mobile_amazon_height", data[placement]["mobile_amazon_height"]);
|
this.set("mobile_amazon_height", data[placement]["mobile_amazon_height"]);
|
||||||
this.set("mobile_amazon_width", data[placement]["mobile_amazon_width"]);
|
this.set("mobile_amazon_width", data[placement]["mobile_amazon_width"]);
|
||||||
this._super();
|
super.init();
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("amazon_width", "amazon_height")
|
@discourseComputed("amazon_width", "amazon_height")
|
||||||
adWrapperStyle(w, h) {
|
adWrapperStyle(w, h) {
|
||||||
return htmlSafe(`width: ${w}px; height: ${h}px;`);
|
return htmlSafe(`width: ${w}px; height: ${h}px;`);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("mobile_amazon_width", "mobile_amazon_height")
|
@discourseComputed("mobile_amazon_width", "mobile_amazon_height")
|
||||||
adWrapperStyleMobile(w, h) {
|
adWrapperStyleMobile(w, h) {
|
||||||
return htmlSafe(`width: ${w}px; height: ${h}px;`);
|
return htmlSafe(`width: ${w}px; height: ${h}px;`);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("mobile_amazon_width")
|
@discourseComputed("mobile_amazon_width")
|
||||||
adTitleStyleMobile(w) {
|
adTitleStyleMobile(w) {
|
||||||
return htmlSafe(`width: ${w}px;`);
|
return htmlSafe(`width: ${w}px;`);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("user_input")
|
@discourseComputed("user_input")
|
||||||
userInput(userInput) {
|
userInput(userInput) {
|
||||||
return htmlSafe(`${userInput}`);
|
return htmlSafe(`${userInput}`);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("user_input_mobile")
|
@discourseComputed("user_input_mobile")
|
||||||
userInputMobile(userInput) {
|
userInputMobile(userInput) {
|
||||||
return htmlSafe(`${userInput}`);
|
return htmlSafe(`${userInput}`);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("currentUser.trust_level")
|
@discourseComputed
|
||||||
showToTrustLevel(trustLevel) {
|
showAmazonAds() {
|
||||||
return !(
|
if (!this.currentUser) {
|
||||||
trustLevel && trustLevel > this.siteSettings.amazon_through_trust_level
|
return true;
|
||||||
);
|
}
|
||||||
},
|
|
||||||
|
return this.currentUser.show_amazon_ads;
|
||||||
|
}
|
||||||
|
|
||||||
@discourseComputed("postNumber")
|
@discourseComputed("postNumber")
|
||||||
showAfterPost(postNumber) {
|
showAfterPost(postNumber) {
|
||||||
@@ -187,5 +186,42 @@ export default AdComponent.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.isNthPost(parseInt(this.siteSettings.amazon_nth_post_code, 10));
|
return this.isNthPost(parseInt(this.siteSettings.amazon_nth_post_code, 10));
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
<template>
|
||||||
|
{{#if this.showAd}}
|
||||||
|
{{#if this.site.mobileView}}
|
||||||
|
<div
|
||||||
|
class="amazon-product-links-label"
|
||||||
|
style={{this.adTitleStyleMobile}}
|
||||||
|
><h2>{{i18n "adplugin.advertisement_label"}}</h2></div>
|
||||||
|
<iframe
|
||||||
|
style={{this.adWrapperStyleMobile}}
|
||||||
|
marginwidth="0"
|
||||||
|
marginheight="0"
|
||||||
|
scrolling="no"
|
||||||
|
frameborder="0"
|
||||||
|
src={{this.userInputMobile}}
|
||||||
|
title={{i18n "adplugin.advertisement_label"}}
|
||||||
|
>
|
||||||
|
</iframe>
|
||||||
|
{{else}}
|
||||||
|
<div class="amazon-product-links-label"><h2>{{i18n
|
||||||
|
"adplugin.advertisement_label"
|
||||||
|
}}</h2></div>
|
||||||
|
<div class="container" align="center">
|
||||||
|
<iframe
|
||||||
|
style={{this.adWrapperStyle}}
|
||||||
|
marginwidth="0"
|
||||||
|
marginheight="0"
|
||||||
|
scrolling="no"
|
||||||
|
frameborder="0"
|
||||||
|
src={{this.userInput}}
|
||||||
|
title={{i18n "adplugin.advertisement_label"}}
|
||||||
|
>
|
||||||
|
</iframe>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { htmlSafe } from "@ember/template";
|
||||||
|
import discourseComputed from "discourse/lib/decorators";
|
||||||
|
import AdComponent from "./ad-component";
|
||||||
|
|
||||||
|
export default class CarbonadsAd extends AdComponent {
|
||||||
|
serve_id = null;
|
||||||
|
placement = null;
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.set("serve_id", this.siteSettings.carbonads_serve_id);
|
||||||
|
this.set("placement", this.siteSettings.carbonads_placement);
|
||||||
|
super.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed("serve_id", "placement")
|
||||||
|
url(serveId, placement) {
|
||||||
|
return htmlSafe(
|
||||||
|
`//cdn.carbonads.com/carbon.js?serve=${serveId}&placement=${placement}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed
|
||||||
|
showCarbonAds() {
|
||||||
|
if (!this.currentUser) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.currentUser.show_carbon_ads;
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed(
|
||||||
|
"placement",
|
||||||
|
"serve_id",
|
||||||
|
"showCarbonAds",
|
||||||
|
"showToGroups",
|
||||||
|
"showOnCurrentPage"
|
||||||
|
)
|
||||||
|
showAd(placement, serveId, showCarbonAds, showToGroups, showOnCurrentPage) {
|
||||||
|
return (
|
||||||
|
placement && serveId && showCarbonAds && showToGroups && showOnCurrentPage
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#if this.showAd}}
|
||||||
|
{{! template-lint-disable no-forbidden-elements }}
|
||||||
|
<script src={{this.url}} id="_carbonads_js" async type="text/javascript">
|
||||||
|
</script>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user