Author SHA1 Message Date
Penar Musaraj d6af1d2e20 FEAT: ads.txt support
Adds a plugin setting that holds text content served on a new /ads.txt route.
2019-02-04 16:15:26 -05:00
Neil Lalonde 79d5f144a6 Merge branch 'master' into stable 2019-02-01 14:04:22 -05:00
Neil Lalonde 408b043046 Merge branch 'master' into stable 2019-02-01 11:56:46 -05:00
Penar Musaraj e628bc859b Revert "Add support for ads.txt redirect"
This reverts commit f6c7c2d1af.

Ads.txt redirection can be done directly in core, in admin/customize/permalinks.
2019-01-29 16:02:02 -05:00
Penar Musaraj f6c7c2d1af Add support for ads.txt redirect 2019-01-29 11:06:42 -05:00
Eric Berry a669381a71 Remove need to only allow UUID as CodeFund Property ID (#71)
* Remove need to only allow UUID as CodeFund Property ID

* Do not apply format check
2019-01-29 11:06:26 -05:00
Joffrey JAFFEUX 75a56891d2 Reverts Ember.String.prototype.w monkey patching causing exception
The git blame of the commit is unclear on the reasons leading to this, and how to reproduce a failure.
2019-01-09 21:18:06 +01:00
Gerhard Schlager 0d4e6bb4fa Inherit rubocop config from discourse repo 2019-01-09 21:17:55 +01:00
Neil Lalonde 5eed122002 Merge branch 'master' into stable 2018-11-29 11:05:04 -05:00
Neil Lalonde 4c45a27a72 Merge branch 'master' into stable 2018-09-10 13:48:57 -04:00
Neil Lalonde c838f10467 Merge branch 'master' into stable 2018-07-19 13:50:15 -04:00
Joshua Rosenfeld 8b404b9ffb Add URL to plugin.rb on stable branch 2018-06-19 22:39:51 -04:00
Jeff Wong 97f56a95bd FIX: resolve collision on ember's builtin w string function 2018-05-16 13:58:33 -07:00
Gerhard Schlager 73d010ef49 Merge branch 'master' into stable 2017-12-14 12:26:44 +01:00
Neil Lalonde 8e1041ec75 Merge branch 'master' into stable 2017-12-05 15:19:21 -05:00
Neil Lalonde 40c0a64bb9 Merge branch 'master' into stable 2017-11-13 16:27:57 -05:00
Neil Lalonde 3f71c80e89 Merge branch 'master' into stable 2017-11-08 13:39:37 -05:00
Guo Xiang Tan 392fd76679 Merge pull request #48 from discourse/merge_master_changes
Merge master changes
2016-12-09 02:19:47 +01:00
208 changed files with 2522 additions and 12622 deletions
-4
View File
@@ -1,4 +0,0 @@
< 3.4.0.beta2-dev: 7685ebf396c93e8accc5a76a81fcec4384a73fa3
< 3.4.0.beta1-dev: da38a4c053b68d7076db4441cfe86b473979945d
< 3.3.0.beta1-dev: 062efc8a547c19474eaeefae464837d63a5e5fb3
3.1.999: 30c49eb50d6d16fcf82bace3da0e1972b7b220c0
+105
View File
@@ -0,0 +1,105 @@
{
"env": {
"jasmine": true,
"node": true,
"mocha": true,
"browser": true,
"builtin": true
},
"parserOptions": {
"ecmaVersion": 7,
"sourceType": "module"
},
"globals":
{"Ember":true,
"jQuery":true,
"$":true,
"RSVP":true,
"Discourse":true,
"Em":true,
"PreloadStore":true,
"Handlebars":true,
"I18n":true,
"bootbox":true,
"module":true,
"moduleFor":true,
"moduleForComponent":true,
"Pretender":true,
"sandbox":true,
"controllerFor":true,
"test":true,
"ok":true,
"not":true,
"expect":true,
"equal":true,
"visit":true,
"andThen":true,
"click":true,
"currentPath":true,
"currentRouteName":true,
"currentURL":true,
"fillIn":true,
"keyEvent":true,
"triggerEvent":true,
"count":true,
"exists":true,
"visible":true,
"invisible":true,
"asyncRender":true,
"selectDropdown":true,
"asyncTestDiscourse":true,
"fixture":true,
"find":true,
"sinon":true,
"moment":true,
"start":true,
"_":true,
"alert":true,
"containsInstance":true,
"deepEqual":true,
"notEqual":true,
"define":true,
"require":true,
"requirejs":true,
"hasModule":true,
"Blob":true,
"File":true},
"rules": {
"block-scoped-var": 2,
"dot-notation": 0,
"eqeqeq": [
2,
"allow-null"
],
"guard-for-in": 2,
"no-bitwise": 2,
"no-caller": 2,
"no-cond-assign": 0,
"no-debugger": 2,
"no-empty": 0,
"no-eval": 2,
"no-extend-native": 2,
"no-extra-parens": 0,
"no-irregular-whitespace": 2,
"no-iterator": 2,
"no-loop-func": 2,
"no-multi-str": 2,
"no-new": 2,
"no-plusplus": 0,
"no-proto": 2,
"no-script-url": 2,
"no-sequences": 2,
"no-shadow": 2,
"no-undef": 2,
"no-unused-vars": 2,
"no-with": 2,
"semi": 2,
"strict": 0,
"valid-typeof": 2,
"wrap-iife": [
2,
"inside"
]
},
"parser": "babel-eslint"
}
-11
View File
@@ -1,11 +0,0 @@
name: Discourse Plugin
on:
push:
branches:
- main
pull_request:
jobs:
ci:
uses: discourse/.github/.github/workflows/discourse-plugin.yml@v1
+2 -3
View File
@@ -2,8 +2,7 @@
log/*.log
pkg/
auto_generated
Gemfile.lock
.DS_Store
*.swp
node_modules
yarn-error.log
.rubocop-https---raw-githubusercontent-com-discourse-*
.rubocop-https---raw-githubusercontent-com-discourse-discourse-master--rubocop-yml
-2
View File
@@ -1,2 +0,0 @@
engine-strict = true
auto-install-peers = false
-1
View File
@@ -1 +0,0 @@
module.exports = require("@discourse/lint-configs/prettier");
+1 -5
View File
@@ -1,5 +1 @@
inherit_gem:
rubocop-discourse: stree-compat.yml
RSpec/NamedSubject:
Enabled: false
inherit_from: https://raw.githubusercontent.com/discourse/discourse/master/.rubocop.yml
-2
View File
@@ -1,2 +0,0 @@
--print-width=100
--plugins=plugin/trailing_comma,plugin/disable_auto_ternary
-1
View File
@@ -1 +0,0 @@
module.exports = require("@discourse/lint-configs/template-lint");
+15
View File
@@ -0,0 +1,15 @@
[main]
host = https://www.transifex.com
lang_map = el_GR: el, es_ES: es, fr_FR: fr, hu_HU: hu, ko_KR: ko, pt_PT: pt, sk_SK: sk, vi_VN: vi
[discourse-org.discourse-adpluginclientenyml]
file_filter = config/locales/client.<lang>.yml
source_file = config/locales/client.en.yml
source_lang = en
type = YML
[discourse-org.discourse-adpluginserverenyml]
file_filter = config/locales/server.<lang>.yml
source_file = config/locales/server.en.yml
source_lang = en
type = YML
+2 -5
View File
@@ -1,8 +1,5 @@
# frozen_string_literal: true
source "https://rubygems.org"
source 'https://rubygems.org'
group :development do
gem "rubocop-discourse"
gem "syntax_tree"
gem 'translations-manager', git: 'https://github.com/discourse/translations-manager.git'
end
-87
View File
@@ -1,87 +0,0 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (7.1.3.3)
base64
bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
minitest (>= 5.1)
mutex_m
tzinfo (~> 2.0)
ast (2.4.2)
base64 (0.2.0)
bigdecimal (3.1.8)
concurrent-ruby (1.2.3)
connection_pool (2.4.1)
drb (2.2.1)
i18n (1.14.5)
concurrent-ruby (~> 1.0)
json (2.7.2)
language_server-protocol (3.17.0.3)
minitest (5.23.1)
mutex_m (0.2.0)
parallel (1.24.0)
parser (3.3.1.0)
ast (~> 2.4.1)
racc
prettier_print (1.2.1)
racc (1.8.0)
rack (3.0.11)
rainbow (3.1.1)
regexp_parser (2.9.2)
rexml (3.3.9)
rubocop (1.64.0)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.31.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.31.3)
parser (>= 3.3.1.0)
rubocop-capybara (2.20.0)
rubocop (~> 1.41)
rubocop-discourse (3.8.0)
activesupport (>= 6.1)
rubocop (>= 1.59.0)
rubocop-capybara (>= 2.0.0)
rubocop-factory_bot (>= 2.0.0)
rubocop-rails (>= 2.25.0)
rubocop-rspec (>= 2.25.0)
rubocop-factory_bot (2.25.1)
rubocop (~> 1.41)
rubocop-rails (2.25.0)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.33.0, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
rubocop-rspec (2.29.2)
rubocop (~> 1.40)
rubocop-capybara (~> 2.17)
rubocop-factory_bot (~> 2.22)
rubocop-rspec_rails (~> 2.28)
rubocop-rspec_rails (2.28.3)
rubocop (~> 1.40)
ruby-progressbar (1.13.0)
syntax_tree (6.2.0)
prettier_print (>= 1.2.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (2.5.0)
PLATFORMS
ruby
DEPENDENCIES
rubocop-discourse
syntax_tree
BUNDLED WITH
2.5.10
-22
View File
@@ -1,22 +0,0 @@
Copyright (c) 2019 Discourse
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+38 -80
View File
@@ -1,26 +1,17 @@
# Official Discourse Advertising Plugin
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.
**Authors**: [Sarah Ni](https://github.com/cyberkoi) & [Vi Nguyen](https://github.com/ladydanger)
**Version**: 1.2.5
**Contributors**: See [credits section](#credits) below
**Version**: 1.0.1
**Contributors**: See credits section below
**License**: MIT License
**Supported Discourse Version**: 1.4
**Supported Ad Platforms**:
* House Ads: Your own ads served from Discourse
* [Google Adsense](http://www.google.com.au/adsense/start/why-adsense.html)
* [Google Double Click for Publishers](https://www.google.com/dfp)
* [Amazon Affiliates](http://affiliate-program.amazon.com) - Banner and Product Link Ads
* [Carbon Ads](https://www.carbonads.net/)
* [AdButler](https://www.adbutler.com/)
* [CodeFund](https://codefund.io) - Ethical Ad Platform for Developers
## Quick Start in 3 Steps
@@ -36,7 +27,7 @@ For non-docker or local development installation (those with programming experie
### Step 1 - Install the Official Discourse Advertising Plugin
As seen in a [how-to on meta.discourse.org](https://meta.discourse.org/t/install-plugins-in-discourse/19157), simply **add the plugin's repository url to your container's app.yml file**:
As seen in a [how-to on meta.discourse.org](https://meta.discourse.org/t/advanced-troubleshooting-with-docker/15927#Example:%20Install%20a%20plugin), simply **add the plugin's repository url to your container's app.yml file**:
```yml
hooks:
@@ -59,18 +50,6 @@ git pull
There are 2 easy steps for configuring your Discourse settings to enable advertisements to display in your Discourse forum.
#### House Ads
If you don't want to use an external ad platform, but want to show your own ads, then House Ads are for you!
Define your ads by going to the Admin section of your Discourse forum, and go to the Plugins section.
On the left, you should see a link called "House Ads".
Begin by creating your ads. Give each a short descriptive name and enter the html for each.
Style them using a custom theme (Admin > Customize > Themes).
Lastly, click the Settings button in the House Ads UI and choose which of your ads to show in each of
the ad slots. The ads will start showing as soon as you add them to slots.
#### Step 2(a) - Choose Your Advertisement Platform
<ul>
@@ -78,11 +57,9 @@ the ad slots. The ads will start showing as soon as you add them to slots.
<li>Click on Settings and a left vertical navigation bar should appear.</li>
<li>Choose your advertisement platform.</li>
<ul>
<li>House Ads - if you want to create and serve ads from your Discourse instance.</li>
<li>Adsense - if using Adsense as your advertisement platform.</li>
<li>DFP - if using the DoubleClick for Publishers advertisement platform.</li>
<li>Carbon Ads - if using the Carbon Ads advertisement platform.</li>
<li>AdButler - if using the AdButler advertisement platform.</li>
<li>CodeFund - if using the CodeFund ethical advertisement platform.</li>
</ul>
</ul>
@@ -96,47 +73,20 @@ the ad slots. The ads will start showing as soon as you add them to slots.
##### Adsense Advertisement Tag to Discourse's Site Settings
![image](https://user-images.githubusercontent.com/5862206/214489271-32ce230f-9f79-441e-9d7a-c5488ebb8c8a.png)
![](https://www.dropbox.com/sc/pguxq17zo2rovyd/AAD--LTH_IIgVhgczoaY1Ljva?dl=1)
##### DoubleClick for Publishers' Advertisement Tag to Discourse's Site Settings
![image](https://user-images.githubusercontent.com/5862206/214489324-8554a996-1876-432b-a686-e1add3b96ec4.png)
![](https://www.dropbox.com/sc/0inoc1iduux0gsf/AADi8tfKX9S6Tx9S8RndcUE8a?dl=1)
##### Amazon Affiliates' Advertisement Tag to Discourse's Site Settings
Only for Product Link and Banner Ads.
![image](https://user-images.githubusercontent.com/5862206/214489360-8829291b-8571-4deb-a867-139e823ebdea.png)
![](https://www.dropbox.com/sc/l67fb5c3tl8bq3d/AAAAMmccMW3kkIeBR7cBdWoFa?dl=1)
##### Carbon Ads Script Tag to Discourse's Site Settings
##### CodeFund Embed Tag to Discourse's Site Settings
![adpluginexample](https://user-images.githubusercontent.com/5862206/214489455-234a3812-3606-47bf-9e49-cdaa3d1e3b9c.png)
##### AdButler Ads Zone URL to Discourse's Site Settings
This plugin only support AdButler "Standard Zones". Text and VAST are not supported.
If you browse to a zone in the AdButler admin, then you can find the Publisher ID (PPPPPP) and the Zone ID (ZZZZZZ) in the URL of your browser's address bar:
`https://admin.adbutler.com/?ID=PPPPPP&p=textadzone.view&zoneID=ZZZZZZ`
Configure the ads in Admin > Settings > AdButler.
Enter the publisher id in the "adbutler publisher id" setting, and enter the Zone IDs in the different
zone id settings as desired.
By default, ads are assumed to be size 728 x 90, or 320 x 50 in mobile view.
To use different size ads, customize using CSS in your site's theme. Override the following CSS:
```css
.adbutler-ad {
width: 728px;
height: 90px;
}
.adbutler-mobile-ad {
width: 320px;
height: 50px;
}
```
![CodeFund Instructions](https://s3-us-west-2.amazonaws.com/codesponsor/discourse-codefund-instructions.png)
### Step 3 - See Your Ad
@@ -147,11 +97,9 @@ Once you've configured your settings and your advertising platform has ads that
In this section, we go into more detail on:
* Available Locations for Ad Display
* Ad Sizes Supported
* Trust Levels
* Personal messages
* Groups
* Categories
* Tags
* Languages Supported
### Available Locations for Ad Display
@@ -164,7 +112,26 @@ The following are available locations along with a description and an image show
| Topic Above Suggested | Ad will appear in the footer above suggested topics of all Discourse forum topics |
| Post Bottom & Nth Post | Ad will appear on the stipulated nth post within a topic. So if you have 5 posts in a topic and you want the ad to display after on the 2nd post, put 2 in ```ad_platform_nth_post_code```. |
![adplugin2](https://user-images.githubusercontent.com/5862206/214489128-2e0a9520-ffa5-47a9-81f8-27609b2c9975.jpeg)
![](https://www.dropbox.com/sc/rm5bcn8c85niul1/AAAUVW-hn56XtCl_XTNlE19Ra?dl=1)
### Advertisement Sizes Supported
This plugin supports the following ad sizes for the following locations.
All locations except post bottom | Post bottom location | Mobile
--- | --- | ---
728 x 90 | 728 x 90 | 320 x 50
336 x 280 | 336 x 280 |
300 x 250 | 300 x 250 |
970 x 90 | 970 x 90 |
468 x 60 | 468 x 60 |
234 x 60 | 234 x 60 |
125 x 125 | |
180 x 150 | |
200 x 200 | |
250 x 250 | |
### Trust Levels
@@ -178,21 +145,12 @@ You can use the ```ad_platform_through_trust_level``` dropdown to disable ads fo
To find more about trust levels in Discourse, refer to [Discourse's posts on trust levels](https://meta.discourse.org/t/what-do-user-trust-levels-do/4924)
### Personal messages
### Languages Supported
By default, ads won't be shown in personal messages. To enable ads in personal messages, use the "no ads for personal messages" setting.
### Groups
To give some users an ad-free experience, put the users in groups and add those groups to the "no ads for groups" setting.
### Categories
To disable ads in certain categories, add them to the "no ads for categories" setting. Also consider using the "no ads for restricted categories" to disable ads in all categories that have read access restrictions.
### Tags
Individual topics can have ads disabled by using tags, and entering those tags in the "no ads for tags" setting. This is useful if some topics violate ad network policies.
* Chinese (Simplified)
* English
* French
* Spanish
## Other Installation
@@ -240,4 +198,4 @@ Open an Issue on this repository to start a chat.
**Our Coaches**: Very special thank you to our coaches and honorary coach - [@georg](https://github.com/georg), [@betaass](https://github.com/betaass), [@adelsmee](https://github.com/adelsmee), [@davich](https://github.com/davich), [@link664](https://github.com/link664), [@tomjadams](https://github.com/tomjadams), [@compactcode](https://github.com/compactcode), [@joffotron](https://github.com/joffotron), [@jocranford](https://github.com/jocranford), [@saramic](https://github.com/saramic), [@madpilot](https://github.com/madpilot), [@catkins](https://github.com/catkins)
**Rails Girls**: Thanks [@sareg0](https://github.com/sareg0) and the Rails Girls Team for the opportunity to participate in Rails Girls Summer of Code 2015.
<p>To create this plugin we referenced the <a href="https://github.com/discourse/discourse-google-dfp">original dfp plugin</a> (created by <a href="https://github.com/nlalonde">@nlalonde</a>) and the <a href="https://meta.discourse.org/t/google-adsense-plugin/11763/133">adsense plugin</a>.</p>
<p>To create this plugin we referenced the <a href="https://github.com/discourse/discourse-google-dfp">original dfp plugin</a> (created by <a href="https://github.com/search?q=neil+lalonde&ref=opensearch&type=Users">nlalonde</a>) and the <a href="https://meta.discourse.org/t/google-adsense-plugin/11763/133">adsense plugin</a>.</p>
@@ -1,10 +0,0 @@
export default {
resource: "admin.adminPlugins",
path: "/plugins",
map() {
this.route("houseAds", { path: "/pluginad/house_creatives" }, function () {
this.route("index", { path: "/" });
this.route("show", { path: "/:ad_id" });
});
},
};
@@ -1,7 +0,0 @@
import CategorySelector from "select-kit/components/category-selector";
export default class HouseAdsCategorySelector extends CategorySelector {
get value() {
return this.selectedCategories.map((c) => c.id);
}
}
@@ -1,44 +0,0 @@
import { action, computed } from "@ember/object";
import { classNames } from "@ember-decorators/component";
import { makeArray } from "discourse-common/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);
}
// TODO: kept for legacy, remove when Discourse is 2.5
mutateValues(values) {
this.set("settingValue", values.join(this.tokenSeparator));
}
computeValues() {
return this.settingValue.split(this.tokenSeparator).filter(Boolean);
}
@computed("choices")
get content() {
return makeArray(this.choices);
}
@action
onChange(value) {
const settingValue = makeArray(value).join(this.tokenSeparator);
this.onChange?.(settingValue);
}
}
@@ -1,13 +0,0 @@
<label for={{this.name}}>{{this.title}}</label>
{{house-ads-chooser
settingValue=this.adValue
choices=this.adNames
onChange=(action (mut this.adValue))
}}
<div class="setting-controls">
{{#if this.changed}}
<DButton class="ok" @action={{action "save"}} @icon="check" />
<DButton class="cancel" @action={{action "cancel"}} @icon="times" />
{{/if}}
</div>
<p class="help">{{this.help}}</p>
@@ -1,8 +0,0 @@
import { mapBy } from "@ember/object/computed";
import { classNames } from "@ember-decorators/component";
import HouseAdsSetting from "discourse/plugins/discourse-adplugin/discourse/components/house-ads-setting";
@classNames("house-ads-setting house-ads-list-setting")
export default class HouseAdsListSetting extends HouseAdsSetting {
@mapBy("allAds", "name") adNames;
}
@@ -1,9 +0,0 @@
<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="times" />
{{/if}}
</div>
<p class="help">{{this.help}}</p>
@@ -1,58 +0,0 @@
import Component from "@ember/component";
import { action } from "@ember/object";
import { classNames } from "@ember-decorators/component";
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { i18n, propertyNotEqual } from "discourse/lib/computed";
import I18n from "I18n";
@classNames("house-ads-setting")
export default class HouseAdsSetting extends Component {
adValue = "";
saving = false;
savingStatus = "";
@i18n("name", "admin.adplugin.house_ads.%@.title") title;
@i18n("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.t("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.t("saved"),
});
})
.catch(popupAjaxError)
.finally(() => {
this.setProperties({
saving: false,
savingStatus: "",
});
});
}
}
@action
cancel() {
this.set("adValue", this.get("value"));
}
}
@@ -1,18 +0,0 @@
import { htmlSafe } from "@ember/template";
import DModal from "discourse/components/d-modal";
import i18n from "discourse-common/helpers/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;
@@ -1,8 +0,0 @@
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;
}
@@ -1,156 +0,0 @@
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 "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.t("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.t("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)
)
: [];
}
}
@@ -1,5 +0,0 @@
import Controller from "@ember/controller";
export default class AdminPluginsHouseAdsController extends Controller {
loadingAds = true;
}
@@ -1,12 +0,0 @@
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");
}
}
@@ -1,23 +0,0 @@
import { TrackedObject } from "@ember-compat/tracked-built-ins";
import DiscourseRoute from "discourse/routes/discourse";
import I18n from "I18n";
export default class AdminPluginsHouseAdsShow extends DiscourseRoute {
model(params) {
if (params.ad_id === "new") {
return new TrackedObject({
name: I18n.t("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)
)
);
}
}
}
@@ -1,22 +0,0 @@
import EmberObject from "@ember/object";
import { ajax } from "discourse/lib/ajax";
import DiscourseRoute from "discourse/routes/discourse";
export default class AdminPluginsHouseAds extends DiscourseRoute {
settings = null;
model() {
return ajax("/admin/plugins/pluginad/house_creatives.json").then((data) => {
this.set("settings", EmberObject.create(data.settings));
return data.house_ads.map((ad) => EmberObject.create(ad));
});
}
setupController(controller, model) {
controller.setProperties({
model,
houseAdsSettings: this.get("settings"),
loadingAds: false,
});
}
}
@@ -1,51 +0,0 @@
<section class="house-ads-settings content-body">
<div>{{i18n "admin.adplugin.house_ads.description"}}</div>
{{#if this.houseAds.length}}
<form class="form-horizontal">
{{house-ads-list-setting
name="topic_list_top"
value=this.adSettings.topic_list_top
allAds=this.houseAds
adSettings=this.adSettings
}}
{{house-ads-list-setting
name="topic_above_post_stream"
value=this.adSettings.topic_above_post_stream
allAds=this.houseAds
adSettings=this.adSettings
}}
{{house-ads-list-setting
name="topic_above_suggested"
value=this.adSettings.topic_above_suggested
allAds=this.houseAds
adSettings=this.adSettings
}}
{{house-ads-list-setting
name="post_bottom"
value=this.adSettings.post_bottom
allAds=this.houseAds
adSettings=this.adSettings
}}
{{house-ads-list-setting
name="topic_list_between"
value=this.adSettings.topic_list_between
allAds=this.houseAds
adSettings=this.adSettings
}}
<DButton
@label="admin.adplugin.house_ads.more_settings"
@icon="cog"
@action={{route-action "moreSettings"}}
class="btn-default"
/>
</form>
{{else}}
<p>
{{#link-to route="adminPlugins.houseAds.show" model="new"}}
{{i18n "admin.adplugin.house_ads.get_started"}}
{{/link-to}}
</p>
{{/if}}
</section>
@@ -1,78 +0,0 @@
<section class="edit-house-ad content-body">
<h1><TextField @value={{this.buffered.name}} class="house-ad-name" /></h1>
<div class="controls">
<AceEditor
@content={{this.buffered.html}}
@onChange={{fn (mut this.buffered.html)}}
@mode="html"
/>
</div>
<div class="controls">
<div class="visibility-settings">
<div>
<Input
@type="checkbox"
@checked={{this.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={{this.buffered.visible_to_anons}}
/>
<span>{{i18n "admin.adplugin.house_ads.show_to_anons"}}</span>
</div>
<HouseAdsCategorySelector
@categories={{this.site.categories}}
@selectedCategories={{this.selectedCategories}}
@onChange={{this.setCategoryIds}}
@options={{hash allowAny=true}}
class="house-ads-categories"
/>
<div class="description">
{{i18n "admin.adplugin.house_ads.category_chooser_description"}}
</div>
<GroupChooser
@content={{this.site.groups}}
@onChange={{this.setGroupIds}}
@value={{this.selectedGroups}}
class="banner-groups"
/>
<div class="description">
{{i18n "admin.adplugin.house_ads.group_chooser_description"}}
</div>
</div>
<DButton
@action={{this.save}}
@disabled={{this.disabledSave}}
@label="admin.adplugin.house_ads.save"
class="btn-primary save-button"
/>
{{#if this.saving}}
{{this.savingStatus}}
{{else}}
{{#unless this.disabledSave}}
<DButton @action={{this.cancel}} @label="cancel" />
{{/unless}}
{{/if}}
<DButton
@action={{this.openPreview}}
@label="admin.adplugin.house_ads.preview"
/>
<DButton
@action={{this.destroy}}
@label="admin.adplugin.house_ads.delete"
class="btn-danger delete-button"
/>
</div>
</section>

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