merge master

This commit is contained in:
Neil Lalonde 2014-11-06 15:26:38 -05:00
commit 361aca1156
2141 changed files with 36532 additions and 20263 deletions

View File

@ -27,8 +27,8 @@ source_file = plugins/poll/config/locales/client.en.yml
source_lang = en
trans.es_ES = plugins/poll/config/locales/client.es.yml
trans.fr_FR = plugins/poll/config/locales/client.fr.yml
#trans.ko_KR = plugins/poll/config/locales/client.ko.yml
#trans.pt_PT = plugins/poll/config/locales/client.pt.yml
trans.ko_KR = plugins/poll/config/locales/client.ko.yml
trans.pt_PT = plugins/poll/config/locales/client.pt.yml
type = YML
[discourse-org.pollserverenyml]
@ -37,8 +37,8 @@ source_file = plugins/poll/config/locales/server.en.yml
source_lang = en
trans.es_ES = plugins/poll/config/locales/server.es.yml
trans.fr_FR = plugins/poll/config/locales/server.fr.yml
#trans.ko_KR = plugins/poll/config/locales/server.ko.yml
#trans.pt_PT = plugins/poll/config/locales/server.pt.yml
trans.ko_KR = plugins/poll/config/locales/server.ko.yml
trans.pt_PT = plugins/poll/config/locales/server.pt.yml
type = YML
[discourse-org.imgurserverenyml]
@ -47,7 +47,7 @@ source_file = vendor/gems/discourse_imgur/lib/discourse_imgur/locale/server.en.y
source_lang = en
trans.es_ES = vendor/gems/discourse_imgur/lib/discourse_imgur/locale/server.es.yml
trans.fr_FR = vendor/gems/discourse_imgur/lib/discourse_imgur/locale/server.fr.yml
#trans.ko_KR = vendor/gems/discourse_imgur/lib/discourse_imgur/locale/server.ko.yml
trans.ko_KR = vendor/gems/discourse_imgur/lib/discourse_imgur/locale/server.ko.yml
trans.pt_PT = vendor/gems/discourse_imgur/lib/discourse_imgur/locale/server.pt.yml
type = YML
@ -55,38 +55,38 @@ type = YML
file_filter = public/403.<lang>.html
source_file = public/403.html
source_lang = en
# trans.es_ES = public/403.es.html
trans.es_ES = public/403.es.html
trans.fr_FR = public/403.fr.html
# trans.ko_KR = public/403.ko.html
# trans.pt_PT = public/403.pt.html
trans.ko_KR = public/403.ko.html
trans.pt_PT = public/403.pt.html
type = HTML
[discourse-org.422html]
file_filter = public/422.<lang>.html
source_file = public/422.html
source_lang = en
# trans.es_ES = public/422.es.html
trans.es_ES = public/422.es.html
trans.fr_FR = public/422.fr.html
# trans.ko_KR = public/422.ko.html
# trans.pt_PT = public/422.pt.html
trans.ko_KR = public/422.ko.html
trans.pt_PT = public/422.pt.html
type = HTML
[discourse-org.500html]
file_filter = public/500.<lang>.html
source_file = public/500.html
source_lang = en
# trans.es_ES = public/500.es.html
trans.es_ES = public/500.es.html
trans.fr_FR = public/500.fr.html
# trans.ko_KR = public/500.ko.html
# trans.pt_PT = public/500.pt.html
trans.ko_KR = public/500.ko.html
trans.pt_PT = public/500.pt.html
type = HTML
[discourse-org.503html]
file_filter = public/503.<lang>.html
source_file = public/503.html
source_lang = en
# trans.es_ES = public/503.es.html
trans.es_ES = public/503.es.html
trans.fr_FR = public/503.fr.html
# trans.ko_KR = public/503.ko.html
# trans.pt_PT = public/503.pt.html
trans.ko_KR = public/503.ko.html
trans.pt_PT = public/503.pt.html
type = HTML

View File

@ -50,7 +50,7 @@ Anyone wishing to contribute to the **[Discourse/Discourse](https://github.com/d
* use spaces around operators, after commas, colons, semicolons, around `{` and before `}`
* no space after `(`, `[` or before `]`, `)`
* use Ruby 1.9 hash syntax: prefer `{ a: 1 }` over `{ :a => 1 }`
* prefer `class << self; def method; end` over `def class.method` for class methods
* prefer `class << self; def method; end` over `def self.method` for class methods
* prefer `{ ... }` over `do ... end` for single-line blocks, avoid using `{ ... }` for multi-line blocks
* avoid `return` when not required

20
Gemfile
View File

@ -88,7 +88,10 @@ gem 'mail', '~> 2.5.4'
gem 'hiredis'
gem 'redis', require: ["redis", "redis/connection/hiredis"]
gem 'active_model_serializers'
# We use some ams 0.8.0 features, need to amend code
# to support 0.9 etc, bench needs to run and ensure no
# perf regressions
gem 'active_model_serializers', '~> 0.8.0'
gem 'onebox'
@ -102,7 +105,6 @@ gem 'message_bus'
gem 'rails_multisite', path: 'vendor/gems/rails_multisite'
gem 'redcarpet', require: false
gem 'airbrake', '3.1.2', require: false # errbit is broken with 3.1.3 for now
gem 'eventmachine'
gem 'fast_xs'
@ -161,7 +163,14 @@ gem 'rack-protection' # security
# in production environments by default.
# allow everywhere for now cause we are allowing asset debugging in prd
group :assets do
gem 'sass-rails', '~> 4.0.2'
if rails_master?
gem 'sass-rails', git: 'https://github.com/rails/sass-rails.git'
else
# later is breaking our asset compliation extensions
gem 'sass-rails', '4.0.2'
end
gem 'uglifier'
gem 'rtlit', require: false # for css rtling
end
@ -172,10 +181,13 @@ group :test do
end
group :test, :development do
# while upgrading to 3
gem 'rspec', '2.99.0'
gem 'mock_redis'
gem 'listen', '0.7.3', require: false
gem 'certified', require: false
gem 'fabrication', require: false
# later appears to break Fabricate(:topic, category: category)
gem 'fabrication', '2.9.8', require: false
gem 'qunit-rails'
gem 'mocha', require: false
gem 'rb-fsevent', require: RUBY_PLATFORM =~ /darwin/i ? 'rb-fsevent' : false

View File

@ -6,40 +6,37 @@ PATH
GEM
remote: https://rubygems.org/
specs:
actionmailer (4.1.5)
actionpack (= 4.1.5)
actionview (= 4.1.5)
mail (~> 2.5.4)
actionpack (4.1.5)
actionview (= 4.1.5)
activesupport (= 4.1.5)
actionmailer (4.1.7)
actionpack (= 4.1.7)
actionview (= 4.1.7)
mail (~> 2.5, >= 2.5.4)
actionpack (4.1.7)
actionview (= 4.1.7)
activesupport (= 4.1.7)
rack (~> 1.5.2)
rack-test (~> 0.6.2)
actionpack-action_caching (1.1.1)
actionpack (>= 4.0.0, < 5.0)
actionview (4.1.5)
activesupport (= 4.1.5)
actionview (4.1.7)
activesupport (= 4.1.7)
builder (~> 3.1)
erubis (~> 2.7.0)
active_model_serializers (0.8.1)
active_model_serializers (0.8.2)
activemodel (>= 3.0)
activemodel (4.1.5)
activesupport (= 4.1.5)
activemodel (4.1.7)
activesupport (= 4.1.7)
builder (~> 3.1)
activerecord (4.1.5)
activemodel (= 4.1.5)
activesupport (= 4.1.5)
activerecord (4.1.7)
activemodel (= 4.1.7)
activesupport (= 4.1.7)
arel (~> 5.0.0)
activesupport (4.1.5)
activesupport (4.1.7)
i18n (~> 0.6, >= 0.6.9)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.1)
tzinfo (~> 1.1)
addressable (2.3.6)
airbrake (3.1.2)
activesupport
builder
annotate (2.6.5)
activerecord (>= 2.3.0)
rake (>= 0.8.7)
@ -57,14 +54,14 @@ GEM
builder (3.2.2)
celluloid (0.15.2)
timers (~> 1.1.0)
certified (0.1.1)
certified (1.0.0)
coderay (1.1.0)
connection_pool (2.0.0)
crass (0.2.1)
daemons (1.1.9)
debug_inspector (0.0.2)
diff-lcs (1.2.5)
docile (1.1.3)
docile (1.1.5)
dotenv (0.11.1)
dotenv-deployment (~> 0.0.2)
dotenv-deployment (0.0.2)
@ -84,7 +81,7 @@ GEM
handlebars-source (~> 1.0)
erubis (2.7.0)
eventmachine (1.0.3)
excon (0.37.0)
excon (0.39.6)
execjs (2.2.1)
exifr (1.1.3)
fabrication (2.9.8)
@ -99,9 +96,9 @@ GEM
rake
rake-compiler
fast_xs (0.8.0)
fastimage (1.6.0)
fastimage (1.6.3)
addressable (~> 2.3, >= 2.3.5)
ffi (1.9.3)
ffi (1.9.5)
flamegraph (0.0.5)
fast_stack
fog (1.22.1)
@ -110,22 +107,22 @@ GEM
fog-json
ipaddress (~> 0.5)
nokogiri (~> 1.5, >= 1.5.11)
fog-brightbox (0.1.1)
fog-brightbox (0.5.1)
fog-core (~> 1.22)
fog-json
inflecto
fog-core (1.22.0)
fog-core (1.24.0)
builder
excon (~> 0.33)
excon (~> 0.38)
formatador (~> 0.2)
mime-types
net-scp (~> 1.1)
net-ssh (>= 2.1.3)
fog-json (1.0.0)
multi_json (~> 1.0)
foreman (0.63.0)
dotenv (>= 0.7)
thor (>= 0.13.6)
foreman (0.75.0)
dotenv (~> 0.11.1)
thor (~> 0.19.1)
formatador (0.2.5)
fspath (2.0.6)
gctools (0.2.3)
@ -133,8 +130,8 @@ GEM
sorcerer (>= 0.3.7)
guess_html_encoding (0.0.9)
handlebars-source (1.3.0)
hashie (2.0.5)
highline (1.6.20)
hashie (3.3.1)
highline (1.6.21)
hike (1.2.3)
hiredis (0.5.2)
htmlentities (4.3.2)
@ -146,20 +143,19 @@ GEM
in_threads (~> 1.2.0)
progress (~> 3.0.0)
image_size (1.1.5)
in_threads (1.2.0)
in_threads (1.2.2)
inflecto (0.0.2)
ipaddress (0.8.0)
jquery-rails (3.1.0)
jquery-rails (3.1.2)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
json (1.8.1)
jwt (0.1.11)
multi_json (>= 1.5)
jwt (1.0.0)
kgio (2.9.2)
librarian (0.1.2)
highline
thor (~> 0.15)
libv8 (3.16.14.3)
libv8 (3.16.14.7)
listen (0.7.3)
logster (0.1.6)
lru_redux (0.8.1)
@ -167,7 +163,7 @@ GEM
mime-types (~> 1.16)
treetop (~> 1.4.8)
memory_profiler (0.0.4)
message_bus (0.9.5)
message_bus (1.0.5)
eventmachine
rack (>= 1.1.3)
redis
@ -175,10 +171,10 @@ GEM
method_source (0.8.2)
mime-types (1.25.1)
mini_portile (0.6.0)
minitest (5.4.0)
mocha (1.0.0)
minitest (5.4.2)
mocha (1.1.0)
metaclass (~> 0.0.1)
mock_redis (0.11.0)
mock_redis (0.13.2)
moneta (0.8.0)
msgpack (0.5.8)
multi_json (1.10.1)
@ -191,34 +187,34 @@ GEM
netrc (0.7.7)
nokogiri (1.6.3.1)
mini_portile (= 0.6.0)
nokogumbo (1.1.9)
nokogumbo (1.1.12)
nokogiri
oauth (0.4.7)
oauth2 (0.9.3)
oauth2 (1.0.0)
faraday (>= 0.8, < 0.10)
jwt (~> 0.1.8)
jwt (~> 1.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (~> 1.2)
oj (2.10.0)
omniauth (1.2.1)
hashie (>= 1.2, < 3)
oj (2.10.2)
omniauth (1.2.2)
hashie (>= 1.2, < 4)
rack (~> 1.0)
omniauth-facebook (1.6.0)
omniauth-oauth2 (~> 1.1)
omniauth-facebook (2.0.0)
omniauth-oauth2 (~> 1.2)
omniauth-github-discourse (1.1.2)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1)
omniauth-google-oauth2 (0.2.4)
omniauth (~> 1.0)
omniauth-google-oauth2 (0.2.5)
omniauth (> 1.0)
omniauth-oauth2 (~> 1.1)
omniauth-oauth (1.0.1)
oauth
omniauth (~> 1.0)
omniauth-oauth2 (1.1.2)
omniauth-oauth2 (1.2.0)
faraday (>= 0.8, < 0.10)
multi_json (~> 1.3)
oauth2 (~> 0.9.3)
oauth2 (~> 1.0)
omniauth (~> 1.2)
omniauth-openid (1.0.1)
omniauth (~> 1.0)
@ -226,7 +222,7 @@ GEM
omniauth-twitter (1.0.1)
multi_json (~> 1.3)
omniauth-oauth (~> 1.0)
onebox (1.4.5)
onebox (1.5.3)
moneta (~> 0.7)
multi_json (~> 1.7)
mustache (~> 0.99)
@ -236,96 +232,99 @@ GEM
ruby-openid
pg (0.15.1)
polyglot (0.3.5)
progress (3.0.0)
pry (0.9.12.6)
coderay (~> 1.0)
method_source (~> 0.8)
progress (3.0.1)
pry (0.10.1)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
pry-nav (0.2.3)
pry (~> 0.9.10)
pry-nav (0.2.4)
pry (>= 0.9.10, < 0.11.0)
pry-rails (0.3.2)
pry (>= 0.9.10)
puma (2.7.1)
puma (2.9.1)
rack (>= 1.1, < 2.0)
qunit-rails (0.0.7)
railties
rack (1.5.2)
rack-mini-profiler (0.9.1)
rack-mini-profiler (0.9.2)
rack (>= 1.1.3)
rack-openid (1.3.1)
rack (>= 1.1.0)
ruby-openid (>= 2.1.8)
rack-protection (1.5.2)
rack-protection (1.5.3)
rack
rack-test (0.6.2)
rack (>= 1.0)
rails (4.1.5)
actionmailer (= 4.1.5)
actionpack (= 4.1.5)
actionview (= 4.1.5)
activemodel (= 4.1.5)
activerecord (= 4.1.5)
activesupport (= 4.1.5)
rails (4.1.7)
actionmailer (= 4.1.7)
actionpack (= 4.1.7)
actionview (= 4.1.7)
activemodel (= 4.1.7)
activerecord (= 4.1.7)
activesupport (= 4.1.7)
bundler (>= 1.3.0, < 2.0)
railties (= 4.1.5)
railties (= 4.1.7)
sprockets-rails (~> 2.0)
rails-observers (0.1.2)
activemodel (~> 4.0)
railties (4.1.5)
actionpack (= 4.1.5)
activesupport (= 4.1.5)
railties (4.1.7)
actionpack (= 4.1.7)
activesupport (= 4.1.7)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
raindrops (0.13.0)
rake (10.3.2)
rake-compiler (0.9.2)
rake-compiler (0.9.3)
rake
rb-fsevent (0.9.4)
rb-inotify (0.9.3)
rb-inotify (0.9.5)
ffi (>= 0.5.0)
rbtrace (0.4.4)
rbtrace (0.4.5)
ffi (>= 1.0.6)
msgpack (>= 0.4.3)
trollop (>= 1.16.2)
redcarpet (3.1.2)
redis (3.0.7)
redis-namespace (1.4.1)
redis (~> 3.0.4)
redis (3.1.0)
redis-namespace (1.5.1)
redis (~> 3.0, >= 3.0.4)
ref (1.0.5)
rest-client (1.7.2)
mime-types (>= 1.16, < 3.0)
netrc (~> 0.7)
rinku (1.7.3)
rmmseg-cpp (0.2.9)
rspec (2.14.1)
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
rspec-core (2.14.7)
rspec-expectations (2.14.5)
rspec (2.99.0)
rspec-core (~> 2.99.0)
rspec-expectations (~> 2.99.0)
rspec-mocks (~> 2.99.0)
rspec-collection_matchers (1.0.0)
rspec-expectations (>= 2.99.0.beta1)
rspec-core (2.99.2)
rspec-expectations (2.99.2)
diff-lcs (>= 1.1.3, < 2.0)
rspec-given (3.5.4)
given_core (= 3.5.4)
rspec (>= 2.12)
rspec-mocks (2.14.6)
rspec-rails (2.14.1)
rspec-mocks (2.99.2)
rspec-rails (2.99.0)
actionpack (>= 3.0)
activemodel (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
rspec-collection_matchers
rspec-core (~> 2.99.0)
rspec-expectations (~> 2.99.0)
rspec-mocks (~> 2.99.0)
rtlit (0.0.5)
ruby-openid (2.5.0)
ruby-readability (0.6.1)
ruby-readability (0.7.0)
guess_html_encoding (>= 0.0.4)
nokogiri (>= 1.4.2)
sanitize (3.0.0)
nokogiri (>= 1.6.0)
sanitize (3.0.2)
crass (~> 0.2.0)
nokogiri (>= 1.4.4)
nokogumbo (= 1.1.9)
sass (3.2.16)
nokogumbo (= 1.1.12)
sass (3.2.19)
sass-rails (4.0.2)
railties (>= 4.0.0, < 5.0)
sass (~> 3.2.0)
@ -337,19 +336,19 @@ GEM
shoulda (3.5.0)
shoulda-context (~> 1.0, >= 1.0.1)
shoulda-matchers (>= 1.4.1, < 3.0)
shoulda-context (1.1.6)
shoulda-matchers (2.5.0)
shoulda-context (1.2.1)
shoulda-matchers (2.7.0)
activesupport (>= 3.0.0)
sidekiq (3.1.3)
celluloid (>= 0.15.2)
sidekiq (3.2.5)
celluloid (= 0.15.2)
connection_pool (>= 2.0.0)
json
redis (>= 3.0.6)
redis-namespace (>= 1.3.1)
simple-rss (1.3.1)
simplecov (0.8.2)
simplecov (0.9.1)
docile (~> 1.1.0)
multi_json
multi_json (~> 1.0)
simplecov-html (~> 0.8.0)
simplecov-html (0.8.0)
sinatra (1.4.5)
@ -393,7 +392,7 @@ GEM
uglifier (2.5.3)
execjs (>= 0.3.0)
json (>= 1.8.0)
unf (0.1.3)
unf (0.1.4)
unf_ext
unf_ext (0.0.6)
unicorn (4.8.3)
@ -406,8 +405,7 @@ PLATFORMS
DEPENDENCIES
actionpack-action_caching
active_model_serializers
airbrake (= 3.1.2)
active_model_serializers (~> 0.8.0)
annotate
barber
better_errors
@ -417,7 +415,7 @@ DEPENDENCIES
ember-rails
ember-source (= 1.6.0.beta.2)
eventmachine
fabrication
fabrication (= 2.9.8)
fakeweb (~> 1.3.0)
fast_blank
fast_xor
@ -474,13 +472,14 @@ DEPENDENCIES
rest-client
rinku
rmmseg-cpp
rspec (= 2.99.0)
rspec-given
rspec-rails
rtlit
ruby-readability
sanitize
sass
sass-rails (~> 4.0.2)
sass-rails (= 4.0.2)
seed-fu (~> 2.3.3)
shoulda
sidekiq

537
Gemfile_master.lock Normal file
View File

@ -0,0 +1,537 @@
GIT
remote: https://github.com/rails/actionpack-action_caching.git
revision: a9f3f09477b12b51faa6756005eee4103f7f4030
specs:
actionpack-action_caching (1.1.0)
actionpack (>= 4.0.0, < 5.0)
GIT
remote: https://github.com/rails/rails.git
revision: 316962d0922992fbe756521bd7c94a751aa1253e
specs:
actionmailer (4.2.0.beta1)
actionpack (= 4.2.0.beta1)
actionview (= 4.2.0.beta1)
activejob (= 4.2.0.beta1)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.2)
actionpack (4.2.0.beta1)
actionview (= 4.2.0.beta1)
activesupport (= 4.2.0.beta1)
rack (~> 1.6.0.beta)
rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.2)
rails-html-sanitizer (~> 1.0)
actionview (4.2.0.beta1)
activesupport (= 4.2.0.beta1)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.2)
rails-html-sanitizer (~> 1.0)
activejob (4.2.0.beta1)
activesupport (= 4.2.0.beta1)
globalid (>= 0.2.3)
activemodel (4.2.0.beta1)
activesupport (= 4.2.0.beta1)
builder (~> 3.1)
activerecord (4.2.0.beta1)
activemodel (= 4.2.0.beta1)
activesupport (= 4.2.0.beta1)
arel (>= 6.0.0.beta1, < 6.1)
activesupport (4.2.0.beta1)
i18n (>= 0.7.0.beta1, < 0.8)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.1)
tzinfo (~> 1.1)
rails (4.2.0.beta1)
actionmailer (= 4.2.0.beta1)
actionpack (= 4.2.0.beta1)
actionview (= 4.2.0.beta1)
activejob (= 4.2.0.beta1)
activemodel (= 4.2.0.beta1)
activerecord (= 4.2.0.beta1)
activesupport (= 4.2.0.beta1)
bundler (>= 1.3.0, < 2.0)
railties (= 4.2.0.beta1)
sprockets-rails (~> 3.0.0.beta1)
railties (4.2.0.beta1)
actionpack (= 4.2.0.beta1)
activesupport (= 4.2.0.beta1)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
GIT
remote: https://github.com/rails/sass-rails.git
revision: 423178729e7b84addcee78b33891644b1fc1705b
specs:
sass-rails (5.0.0.beta1)
railties (>= 4.0.0, < 5.0)
sass (~> 3.2)
sprockets (~> 2.12)
sprockets-rails (>= 2.0, < 4.0)
PATH
remote: vendor/gems/rails_multisite
specs:
rails_multisite (0.0.1)
GEM
remote: https://rubygems.org/
specs:
active_model_serializers (0.8.2)
activemodel (>= 3.0)
addressable (2.3.6)
airbrake (3.1.2)
activesupport
builder
annotate (2.6.5)
activerecord (>= 2.3.0)
rake (>= 0.8.7)
arel (6.0.0.beta1)
barber (0.4.2)
ember-source
execjs
handlebars-source
better_errors (2.0.0)
coderay (>= 1.0.0)
erubis (>= 2.6.6)
rack (>= 0.9.0)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
builder (3.2.2)
celluloid (0.15.2)
timers (~> 1.1.0)
certified (1.0.0)
coderay (1.1.0)
connection_pool (2.0.0)
crass (0.2.1)
daemons (1.1.9)
debug_inspector (0.0.2)
diff-lcs (1.2.5)
docile (1.1.5)
dotenv (0.11.1)
dotenv-deployment (~> 0.0.2)
dotenv-deployment (0.0.2)
email_reply_parser-discourse (0.6)
ember-data-source (1.0.0.beta.9)
ember-source
ember-rails (0.15.0)
active_model_serializers
barber (>= 0.4.1)
ember-data-source (>= 1.0.0.beta.5)
ember-source (>= 1.1.0)
execjs (>= 1.2)
handlebars-source (> 1.0.0)
jquery-rails (>= 1.0.17)
railties (>= 3.1)
ember-source (1.6.0.beta.2)
handlebars-source (~> 1.0)
erubis (2.7.0)
eventmachine (1.0.3)
excon (0.39.5)
execjs (2.2.1)
exifr (1.1.3)
fabrication (2.11.3)
fakeweb (1.3.0)
faraday (0.9.0)
multipart-post (>= 1.2, < 3)
fast_blank (0.0.2)
fast_stack (0.1.0)
rake
rake-compiler
fast_xor (1.1.3)
rake
rake-compiler
fast_xs (0.8.0)
fastimage (1.6.3)
addressable (~> 2.3, >= 2.3.5)
ffi (1.9.3)
flamegraph (0.0.5)
fast_stack
fog (1.22.1)
fog-brightbox
fog-core (~> 1.22)
fog-json
ipaddress (~> 0.5)
nokogiri (~> 1.5, >= 1.5.11)
fog-brightbox (0.5.0)
fog-core (~> 1.22)
fog-json
inflecto
fog-core (1.24.0)
builder
excon (~> 0.38)
formatador (~> 0.2)
mime-types
net-scp (~> 1.1)
net-ssh (>= 2.1.3)
fog-json (1.0.0)
multi_json (~> 1.0)
foreman (0.75.0)
dotenv (~> 0.11.1)
thor (~> 0.19.1)
formatador (0.2.5)
fspath (2.0.6)
gctools (0.2.3)
given_core (3.5.4)
sorcerer (>= 0.3.7)
globalid (0.2.3)
activesupport (>= 4.1.0)
guess_html_encoding (0.0.9)
handlebars-source (1.3.0)
hashie (3.3.1)
highline (1.6.21)
hike (1.2.3)
hiredis (0.5.2)
htmlentities (4.3.2)
i18n (0.7.0.beta1)
image_optim (0.9.1)
exifr (~> 1.1.3)
fspath (~> 2.0.5)
image_size (~> 1.1.2)
in_threads (~> 1.2.0)
progress (~> 3.0.0)
image_size (1.1.5)
in_threads (1.2.2)
inflecto (0.0.2)
ipaddress (0.8.0)
jquery-rails (3.1.2)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
json (1.8.1)
jwt (1.0.0)
kgio (2.9.2)
librarian (0.1.2)
highline
thor (~> 0.15)
libv8 (3.16.14.3)
listen (0.7.3)
logster (0.1.6)
loofah (2.0.1)
nokogiri (>= 1.5.9)
lru_redux (0.8.1)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
memory_profiler (0.0.4)
message_bus (0.9.5)
eventmachine
rack (>= 1.1.3)
redis
metaclass (0.0.4)
method_source (0.8.2)
mime-types (1.25.1)
mini_portile (0.6.0)
minitest (5.4.1)
mocha (1.1.0)
metaclass (~> 0.0.1)
mock_redis (0.13.2)
moneta (0.8.0)
msgpack (0.5.8)
multi_json (1.10.1)
multi_xml (0.5.5)
multipart-post (2.0.0)
mustache (0.99.6)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
net-ssh (2.9.1)
netrc (0.7.7)
nokogiri (1.6.3.1)
mini_portile (= 0.6.0)
nokogumbo (1.1.12)
nokogiri
oauth (0.4.7)
oauth2 (1.0.0)
faraday (>= 0.8, < 0.10)
jwt (~> 1.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (~> 1.2)
oj (2.10.2)
omniauth (1.2.2)
hashie (>= 1.2, < 4)
rack (~> 1.0)
omniauth-facebook (2.0.0)
omniauth-oauth2 (~> 1.2)
omniauth-github-discourse (1.1.2)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1)
omniauth-google-oauth2 (0.2.5)
omniauth (> 1.0)
omniauth-oauth2 (~> 1.1)
omniauth-oauth (1.0.1)
oauth
omniauth (~> 1.0)
omniauth-oauth2 (1.2.0)
faraday (>= 0.8, < 0.10)
multi_json (~> 1.3)
oauth2 (~> 1.0)
omniauth (~> 1.2)
omniauth-openid (1.0.1)
omniauth (~> 1.0)
rack-openid (~> 1.3.1)
omniauth-twitter (1.0.1)
multi_json (~> 1.3)
omniauth-oauth (~> 1.0)
onebox (1.4.9)
moneta (~> 0.7)
multi_json (~> 1.7)
mustache (~> 0.99)
nokogiri (~> 1.6.1)
openid-redis-store (0.0.2)
redis
ruby-openid
pg (0.15.1)
polyglot (0.3.5)
progress (3.0.1)
pry (0.10.1)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
pry-nav (0.2.4)
pry (>= 0.9.10, < 0.11.0)
pry-rails (0.3.2)
pry (>= 0.9.10)
puma (2.9.0)
rack (>= 1.1, < 2.0)
qunit-rails (0.0.7)
railties
rack (1.6.0.beta)
rack-mini-profiler (0.9.2)
rack (>= 1.1.3)
rack-openid (1.3.1)
rack (>= 1.1.0)
ruby-openid (>= 2.1.8)
rack-protection (1.5.3)
rack
rack-test (0.6.2)
rack (>= 1.0)
rails-deprecated_sanitizer (1.0.2)
activesupport (>= 4.2.0.alpha)
rails-dom-testing (1.0.2)
activesupport
nokogiri (~> 1.6.0)
rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.0)
loofah (~> 2.0)
rails-observers (0.1.2)
activemodel (~> 4.0)
raindrops (0.13.0)
rake (10.3.2)
rake-compiler (0.9.3)
rake
rb-fsevent (0.9.4)
rb-inotify (0.9.5)
ffi (>= 0.5.0)
rbtrace (0.4.5)
ffi (>= 1.0.6)
msgpack (>= 0.4.3)
trollop (>= 1.16.2)
redcarpet (3.1.2)
redis (3.1.0)
redis-namespace (1.5.1)
redis (~> 3.0, >= 3.0.4)
ref (1.0.5)
rest-client (1.7.2)
mime-types (>= 1.16, < 3.0)
netrc (~> 0.7)
rinku (1.7.3)
rmmseg-cpp (0.2.9)
rspec (3.0.0)
rspec-core (~> 3.0.0)
rspec-expectations (~> 3.0.0)
rspec-mocks (~> 3.0.0)
rspec-core (3.0.4)
rspec-support (~> 3.0.0)
rspec-expectations (3.0.4)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.0.0)
rspec-given (3.5.4)
given_core (= 3.5.4)
rspec (>= 2.12)
rspec-mocks (3.0.4)
rspec-support (~> 3.0.0)
rspec-rails (3.0.2)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 3.0.0)
rspec-expectations (~> 3.0.0)
rspec-mocks (~> 3.0.0)
rspec-support (~> 3.0.0)
rspec-support (3.0.4)
rtlit (0.0.5)
ruby-openid (2.5.0)
ruby-readability (0.7.0)
guess_html_encoding (>= 0.0.4)
nokogiri (>= 1.6.0)
sanitize (3.0.2)
crass (~> 0.2.0)
nokogiri (>= 1.4.4)
nokogumbo (= 1.1.12)
sass (3.4.2)
seed-fu (2.3.3)
activerecord (>= 3.1, < 4.2)
activesupport (>= 3.1, < 4.2)
shoulda (3.5.0)
shoulda-context (~> 1.0, >= 1.0.1)
shoulda-matchers (>= 1.4.1, < 3.0)
shoulda-context (1.2.1)
shoulda-matchers (2.7.0)
activesupport (>= 3.0.0)
sidekiq (3.2.3)
celluloid (>= 0.15.2)
connection_pool (>= 2.0.0)
json
redis (>= 3.0.6)
redis-namespace (>= 1.3.1)
simple-rss (1.3.1)
simplecov (0.9.0)
docile (~> 1.1.0)
multi_json
simplecov-html (~> 0.8.0)
simplecov-html (0.8.0)
sinatra (1.4.5)
rack (~> 1.4)
rack-protection (~> 1.4)
tilt (~> 1.3, >= 1.3.4)
slop (3.6.0)
sorcerer (1.0.2)
spork (1.0.0rc4)
spork-rails (4.0.0)
rails (>= 3.0.0, < 5)
spork (>= 1.0rc0)
sprockets (2.12.1)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sprockets-rails (3.0.0.beta1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (~> 2.8)
stackprof (0.2.7)
therubyracer (0.12.1)
libv8 (~> 3.16.14.0)
ref
thin (1.6.2)
daemons (>= 1.0.9)
eventmachine (>= 1.0.0)
rack (>= 1.0.0)
thor (0.19.1)
thread_safe (0.3.4)
tilt (1.4.1)
timecop (0.7.1)
timers (1.1.0)
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
trollop (2.0)
tzinfo (1.2.2)
thread_safe (~> 0.1)
uglifier (2.5.3)
execjs (>= 0.3.0)
json (>= 1.8.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.6)
unicorn (4.8.3)
kgio (~> 2.6)
rack
raindrops (~> 0.7)
PLATFORMS
ruby
DEPENDENCIES
actionpack-action_caching!
active_model_serializers (~> 0.8.0)
airbrake (= 3.1.2)
annotate
barber
better_errors
binding_of_caller
certified
email_reply_parser-discourse
ember-rails
ember-source (= 1.6.0.beta.2)
eventmachine
fabrication
fakeweb (~> 1.3.0)
fast_blank
fast_xor
fast_xs
fastimage
flamegraph
fog (= 1.22.1)
foreman
gctools
handlebars-source (= 1.3.0)
highline
hiredis
htmlentities
image_optim (= 0.9.1)
librarian (>= 0.0.25)
listen (= 0.7.3)
logster
lru_redux
mail (~> 2.5.4)
memory_profiler
message_bus
minitest
mocha
mock_redis
multi_json
mustache
nokogiri
oj
omniauth
omniauth-facebook
omniauth-github-discourse
omniauth-google-oauth2
omniauth-oauth2
omniauth-openid
omniauth-twitter
onebox
openid-redis-store
pg (= 0.15.1)
pry-nav
pry-rails
puma
qunit-rails
rack-mini-profiler
rack-protection
rails!
rails-observers
rails_multisite!
rake
rb-fsevent
rb-inotify (~> 0.9)
rbtrace
redcarpet
redis
rest-client
rinku
rmmseg-cpp
rspec-given
rspec-rails
rtlit
ruby-readability
sanitize
sass
sass-rails!
seed-fu (~> 2.3.3)
shoulda
sidekiq
simple-rss
simplecov
sinatra
spork-rails
stackprof
therubyracer
thin
timecop
uglifier
unf
unicorn

View File

@ -24,7 +24,7 @@ To learn more about the philosophy and goals of the project, [visit **discourse.
2. If you're familiar with how Rails works and are comfortable setting up your own environment, use our [**Discourse Advanced Developer Guide**](docs/DEVELOPER-ADVANCED.md).
Before you get started, ensure you have the following minimum versions: [Ruby 1.9.3+](http://www.ruby-lang.org/en/downloads/), [PostgreSQL 9.1+](http://www.postgresql.org/download/), [Redis 2.6+](http://redis.io/download). If you're having trouble, please see our [**TROUBLESHOOTING GUIDE**](docs/TROUBLESHOOTING.md) first!
Before you get started, ensure you have the following minimum versions: [Ruby 2.0.0+](http://www.ruby-lang.org/en/downloads/), [PostgreSQL 9.1+](http://www.postgresql.org/download/), [Redis 2.6+](http://redis.io/download). If you're having trouble, please see our [**TROUBLESHOOTING GUIDE**](docs/TROUBLESHOOTING.md) first!
## Setting up a Discourse Forum

Binary file not shown.

Before

Width:  |  Height:  |  Size: 762 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 405 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@ -21,7 +21,8 @@ Discourse.ScreenedIpAddressFormComponent = Ember.Component.extend({
actionNames: function() {
return [
{id: 'block', name: I18n.t('admin.logs.screened_ips.actions.block')},
{id: 'do_nothing', name: I18n.t('admin.logs.screened_ips.actions.do_nothing')}
{id: 'do_nothing', name: I18n.t('admin.logs.screened_ips.actions.do_nothing')},
{id: 'allow_admin', name: I18n.t('admin.logs.screened_ips.actions.allow_admin')}
];
}.property(),

View File

@ -2,37 +2,25 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality';
import ObjectController from 'discourse/controllers/object';
export default ObjectController.extend(ModalFunctionality, {
needs: ["adminFlags"],
_agreeFlag: function (actionOnPost) {
var adminFlagController = this.get("controllers.adminFlags");
var post = this.get("content");
var self = this;
return post.agreeFlags(actionOnPost).then(function () {
adminFlagController.removeObject(post);
self.send("closeModal");
}, function () {
bootbox.alert(I18n.t("admin.flags.error"));
});
},
actions: {
agreeFlagHidePost: function () {
var adminFlagController = this.get("controllers.adminFlags");
var post = this.get("content");
var self = this;
return post.agreeFlags("hide").then(function () {
adminFlagController.removeObject(post);
self.send("closeModal");
}, function () {
bootbox.alert(I18n.t("admin.flags.error"));
});
},
agreeFlagKeepPost: function () {
var adminFlagController = this.get("controllers.adminFlags");
var post = this.get("content");
var self = this;
return post.agreeFlags("keep").then(function () {
adminFlagController.removeObject(post);
self.send("closeModal");
}, function () {
bootbox.alert(I18n.t("admin.flags.error"));
});
}
agreeFlagHidePost: function () { return this._agreeFlag("hide"); },
agreeFlagKeepPost: function () { return this._agreeFlag("keep"); },
agreeFlagRestorePost: function () { return this._agreeFlag("restore"); }
}
});

View File

@ -9,7 +9,7 @@ export default Ember.ArrayController.extend({
restoreDisabled: Em.computed.alias("status.restoreDisabled"),
restoreTitle: function() {
if (!Discourse.SiteSettings.allow_restore) {
if (!this.get('status.allowRestore')) {
return I18n.t("admin.backups.operations.restore.is_disabled");
} else if (this.get("status.isOperationRunning")) {
return I18n.t("admin.backups.operation_already_running");
@ -28,11 +28,11 @@ export default Ember.ArrayController.extend({
}
}.property("status.isOperationRunning"),
readOnlyModeTitle: function() { return this._readOnlyModeI18n("title"); }.property("Discourse.isReadOnly"),
readOnlyModeText: function() { return this._readOnlyModeI18n("text"); }.property("Discourse.isReadOnly"),
readOnlyModeTitle: function() { return this._readOnlyModeI18n("title"); }.property("site.isReadOnly"),
readOnlyModeText: function() { return this._readOnlyModeI18n("text"); }.property("site.isReadOnly"),
_readOnlyModeI18n: function(value) {
var action = Discourse.get("isReadOnly") ? "disable" : "enable";
var action = this.site.get("isReadOnly") ? "disable" : "enable";
return I18n.t("admin.backups.read_only." + action + "." + value);
},
@ -45,7 +45,7 @@ export default Ember.ArrayController.extend({
**/
toggleReadOnlyMode: function() {
var self = this;
if (!Discourse.get("isReadOnly")) {
if (!this.site.get("isReadOnly")) {
bootbox.confirm(
I18n.t("admin.backups.read_only.enable.confirm"),
I18n.t("no_value"),
@ -65,11 +65,12 @@ export default Ember.ArrayController.extend({
},
_toggleReadOnlyMode: function(enable) {
var site = this.site;
Discourse.ajax("/admin/backups/readonly", {
type: "PUT",
data: { enable: enable }
}).then(function() {
Discourse.set("isReadOnly", enable);
site.set("isReadOnly", enable);
});
}
});

View File

@ -0,0 +1,49 @@
export default Ember.Controller.extend({
needs: ['modal'],
sample: Em.computed.alias('model.sample'),
errors: Em.computed.alias('model.errors'),
count: Em.computed.alias('model.grant_count'),
count_warning: function() {
if (this.get('count') <= 10) {
return this.get('sample.length') !== this.get('count');
} else {
return this.get('sample.length') !== 10;
}
}.property('count', 'sample.length'),
has_query_plan: function() {
return !!this.get('model.query_plan');
}.property('model.query_plan'),
query_plan_html: function() {
var raw = this.get('model.query_plan'),
returned = "<pre class='badge-query-plan'>";
_.each(raw, function(linehash) {
returned += Handlebars.Utils.escapeExpression(linehash["QUERY PLAN"]);
returned += "<br>";
});
returned += "</pre>";
return returned;
}.property('model.query_plan'),
processed_sample: Ember.computed.map('model.sample', function(grant) {
var i18nKey = 'admin.badges.preview.grant.with',
i18nParams = { username: Handlebars.Utils.escapeExpression(grant.username) };
if (grant.post_id) {
i18nKey += "_post";
i18nParams.link = "<a href='/p/" + grant.post_id + "' data-auto-route='true'>" + Handlebars.Utils.escapeExpression(grant.title) + "</a>";
}
if (grant.granted_at) {
i18nKey += "_time";
i18nParams.time = Handlebars.Utils.escapeExpression(moment(grant.granted_at).format(I18n.t('dates.long_with_year')));
}
return I18n.t(i18nKey, i18nParams);
})
});

View File

@ -1,37 +0,0 @@
import ObjectController from 'discourse/controllers/object';
/**
This is the itemController for `Discourse.AdminBadgesController`. Its main purpose
is to indicate which badge was selected.
@class AdminBadgeController
@extends ObjectController
@namespace Discourse
@module Discourse
**/
export default ObjectController.extend({
/**
Whether this badge has been selected.
@property selected
@type {Boolean}
**/
selected: Discourse.computed.propertyEqual('model.name', 'parentController.selectedItem.name'),
/**
Show the displayName only if it is different from the name.
@property showDisplayName
@type {Boolean}
**/
showDisplayName: Discourse.computed.propertyNotEqual('selectedItem.name', 'selectedItem.displayName'),
/**
Don't allow editing if this is a system badge.
@property readOnly
@type {Boolean}
**/
readOnly: Ember.computed.alias('model.system')
});

View File

@ -0,0 +1,98 @@
import BufferedContent from 'discourse/mixins/buffered-content';
export default Ember.ObjectController.extend(BufferedContent, {
needs: ['admin-badges'],
saving: false,
savingStatus: '',
badgeTypes: Em.computed.alias('controllers.admin-badges.badgeTypes'),
badgeGroupings: Em.computed.alias('controllers.admin-badges.badgeGroupings'),
badgeTriggers: Em.computed.alias('controllers.admin-badges.badgeTriggers'),
protectedSystemFields: Em.computed.alias('controllers.admin-badges.protectedSystemFields'),
readOnly: Ember.computed.alias('buffered.system'),
showDisplayName: Discourse.computed.propertyNotEqual('name', 'displayName'),
canEditDescription: Em.computed.none('buffered.translatedDescription'),
_resetSaving: function() {
this.set('saving', false);
this.set('savingStatus', '');
}.observes('model.id'),
actions: {
save: function() {
if (!this.get('saving')) {
var fields = ['allow_title', 'multiple_grant',
'listable', 'auto_revoke',
'enabled', 'show_posts',
'target_posts', 'name', 'description',
'icon', 'image', 'query', 'badge_grouping_id',
'trigger', 'badge_type_id'],
self = this;
if (this.get('buffered.system')){
var protectedFields = this.get('protectedSystemFields');
fields = _.filter(fields, function(f){
return !_.include(protectedFields,f);
});
}
this.set('saving', true);
this.set('savingStatus', I18n.t('saving'));
var boolFields = ['allow_title', 'multiple_grant',
'listable', 'auto_revoke',
'enabled', 'show_posts',
'target_posts' ];
var data = {},
buffered = this.get('buffered');
fields.forEach(function(field){
var d = buffered.get(field);
if (_.include(boolFields, field)) { d = !!d; }
data[field] = d;
});
var newBadge = !this.get('id'),
model = this.get('model');
this.get('model').save(data).then(function() {
if (newBadge) {
self.get('controllers.admin-badges').pushObject(model);
self.transitionToRoute('adminBadges.show', model.get('id'));
} else {
self.commitBuffer();
self.set('savingStatus', I18n.t('saved'));
}
}).catch(function(error) {
self.set('savingStatus', I18n.t('failed'));
self.send('saveError', error);
}).finally(function() {
self.set('saving', false);
});
}
},
destroy: function() {
var self = this,
adminBadgesController = this.get('controllers.admin-badges'),
model = this.get('model');
if (!model.get('id')) {
self.transitionToRoute('adminBadges.index');
return;
}
return bootbox.confirm(I18n.t("admin.badges.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(result) {
if (result) {
model.destroy().then(function() {
adminBadgesController.removeObject(model);
self.transitionToRoute('adminBadges.index');
}).catch(function() {
bootbox.alert(I18n.t('generic_error'));
});
}
});
}
}
});

View File

@ -1,175 +1 @@
/**
This controller supports the interface for dealing with badges.
@class AdminBadgesController
@extends Ember.ArrayController
@namespace Discourse
@module Discourse
**/
export default Ember.ArrayController.extend({
needs: ['modal'],
itemController: 'admin-badge',
queryParams: ['badgeId'],
badgeId: Em.computed.alias('selectedId'),
/**
ID of the currently selected badge.
@property selectedId
@type {Integer}
**/
selectedId: null,
/**
Badge that is currently selected.
@property selectedItem
@type {Discourse.Badge}
**/
selectedItem: function() {
if (this.get('selectedId') === undefined || this.get('selectedId') === "undefined") {
// New Badge
return this.get('newBadge');
} else {
// Existing Badge
var selectedId = parseInt(this.get('selectedId'));
return this.get('model').filter(function(badge) {
return parseInt(badge.get('id')) === selectedId;
})[0];
}
}.property('selectedId', 'newBadge'),
/**
Unsaved badge, if one exists.
@property newBadge
@type {Discourse.Badge}
**/
newBadge: function() {
return this.get('model').filter(function(badge) {
return badge.get('id') === undefined;
})[0];
}.property('model.@each.id'),
/**
Whether a new unsaved badge exists.
@property newBadgeExists
@type {Discourse.Badge}
**/
newBadgeExists: Em.computed.notEmpty('newBadge'),
/**
We don't allow setting a description if a translation for the given badge
name exists.
@property canEditDescription
@type {Boolean}
**/
canEditDescription: Em.computed.none('selectedItem.translatedDescription'),
/**
Disable saving if the currently selected item is being saved.
@property disableSave
@type {Boolean}
**/
disableSave: Em.computed.alias('selectedItem.saving'),
actions: {
preview: function(badge) {
// TODO wire modal and localize
Discourse.ajax('/admin/badges/preview.json', {
method: 'post',
data: {sql: badge.query, target_posts: !!badge.target_posts}
}).then(function(json){
if(json.error){
bootbox.alert(json.error);
} else {
bootbox.alert(json.grant_count + " badges to be assigned");
}
});
},
/**
Create a new badge and select it.
@method newBadge
**/
createNewBadge: function() {
var badge = Discourse.Badge.create({
name: I18n.t('admin.badges.new_badge')
});
this.pushObject(badge);
this.send('selectBadge', badge);
},
/**
Select a particular badge.
@method selectBadge
@param {Discourse.Badge} badge The badge to be selected
**/
selectBadge: function(badge) {
this.set('selectedId', badge.get('id'));
},
/**
Save the selected badge.
@method save
**/
save: function() {
if (!this.get('disableSave')) {
var fields = ['allow_title', 'multiple_grant',
'listable', 'auto_revoke',
'enabled', 'show_posts',
'target_posts', 'name', 'description',
'icon', 'query', 'badge_grouping_id',
'trigger', 'badge_type_id'];
if(this.get('selectedItem.system')){
var protectedFields = this.get('protectedSystemFields');
fields = _.filter(fields, function(f){
return !_.include(protectedFields,f);
});
}
this.get('selectedItem').save(fields);
}
},
/**
Confirm before destroying the selected badge.
@method destroy
**/
destroy: function() {
// Delete immediately if the selected badge is new.
if (!this.get('selectedItem.id')) {
this.get('model').removeObject(this.get('selectedItem'));
this.set('selectedId', null);
return;
}
var self = this;
return bootbox.confirm(I18n.t("admin.badges.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(result) {
if (result) {
var selected = self.get('selectedItem');
selected.destroy().then(function() {
// Success.
self.set('selectedId', null);
self.get('model').removeObject(selected);
}, function() {
// Failure.
bootbox.alert(I18n.t('generic_error'));
});
}
});
}
}
});
export default Ember.ArrayController.extend();

View File

@ -1,7 +0,0 @@
export default Ember.ArrayController.extend({
actions: {
goToGithub: function() {
window.open('https://github.com/discourse/discourse');
}
}
});

View File

@ -11,6 +11,8 @@ export default Ember.Controller.extend({
versionCheck: null,
problemsCheckMinutes: 1,
showVersionChecks: Discourse.computed.setting('version_checks'),
foundProblems: function() {
return(Discourse.User.currentProp('admin') && this.get('problems') && this.get('problems').length > 0);
}.property('problems'),

View File

@ -10,11 +10,13 @@ export default Ember.ArrayController.extend(Discourse.Presence, {
loading: false,
content: [],
clearBlock: function(row){
row.clearBlock().then(function(){
// feeling lazy
window.location.reload();
});
actions: {
clearBlock: function(row){
row.clearBlock().then(function(){
// feeling lazy
window.location.reload();
});
}
},
show: function() {

View File

@ -2,17 +2,27 @@ export default Ember.ObjectController.extend({
viewMode: 'table',
viewingTable: Em.computed.equal('viewMode', 'table'),
viewingBarChart: Em.computed.equal('viewMode', 'barChart'),
startDate: null,
endDate: null,
refreshing: false,
actions: {
// Changes the current view mode to 'table'
refreshReport: function() {
var self = this;
this.set('refreshing', true);
Discourse.Report.find(this.get('type'), this.get('startDate'), this.get('endDate')).then(function(r) {
self.set('model', r);
}).finally(function() {
self.set('refreshing', false);
});
},
viewAsTable: function() {
this.set('viewMode', 'table');
},
// Changes the current view mode to 'barChart'
viewAsBarChart: function() {
this.set('viewMode', 'barChart');
}
}
});

View File

@ -1,20 +0,0 @@
import DiscourseController from 'discourse/controllers/controller';
export default DiscourseController.extend({
saveDisabled: function() {
if (this.get('saving')) { return true; }
if ((!this.get('content.allow_blank')) && this.blank('content.content')) { return true; }
return false;
}.property('saving', 'content.content'),
actions: {
saveChanges: function() {
var self = this;
self.setProperties({saving: true, saved: false});
self.get('content').save().then(function () {
self.setProperties({saving: false, saved: true});
});
}
}
});

View File

@ -0,0 +1,20 @@
export default Ember.ObjectController.extend({
saving: false,
saved: false,
saveDisabled: function() {
if (this.get('saving')) { return true; }
if ((!this.get('allow_blank')) && Ember.empty(this.get('value'))) { return true; }
return false;
}.property('saving', 'value'),
actions: {
saveChanges: function() {
var self = this;
self.setProperties({saving: true, saved: false});
self.get('model').save().then(function () {
self.setProperties({saving: false, saved: true});
});
}
}
});

View File

@ -0,0 +1,61 @@
import UserField from 'admin/models/user-field';
import BufferedContent from 'discourse/mixins/buffered-content';
export default Ember.ObjectController.extend(BufferedContent, {
needs: ['admin-user-fields'],
editing: Ember.computed.empty('id'),
fieldName: function() {
return UserField.fieldTypeById(this.get('field_type')).get('name');
}.property('field_type'),
flags: function() {
var ret = [];
if (this.get('editable')) {
ret.push(I18n.t('admin.user_fields.editable.enabled'));
}
if (this.get('required')) {
ret.push(I18n.t('admin.user_fields.required.enabled'));
}
return ret.join(', ');
}.property('editable', 'required'),
actions: {
save: function() {
var self = this;
var attrs = this.get('buffered').getProperties('name', 'description', 'field_type', 'editable', 'required');
this.get('model').save(attrs).then(function(res) {
self.set('model.id', res.user_field.id);
self.set('editing', false);
self.commitBuffer();
}).catch(function(e) {
var msg = I18n.t("generic_error");
if (e.responseJSON && e.responseJSON.errors) {
msg = I18n.t("generic_error_with_reason", {error: e.responseJSON.errors.join('. ')});
}
bootbox.alert(msg);
});
},
edit: function() {
this.set('editing', true);
},
destroy: function() {
this.get('controllers.admin-user-fields').send('destroy', this.get('model'));
},
cancel: function() {
var id = this.get('id');
if (Ember.empty(id)) {
this.get('controllers.admin-user-fields').send('destroy', this.get('model'));
} else {
this.rollbackBuffer();
this.set('editing', false);
}
}
}
});

View File

@ -0,0 +1,40 @@
import UserField from 'admin/models/user-field';
export default Ember.ArrayController.extend({
fieldTypes: null,
createDisabled: Em.computed.gte('model.length', 3),
userFieldsDescription: function() {
return I18n.t('admin.user_fields.description');
}.property(),
userFieldsName: function() {
return I18n.t('admin.user_fields.name');
}.property(),
_performDestroy: function(f, model) {
return f.destroy().then(function() {
model.removeObject(f);
});
},
actions: {
createField: function() {
this.pushObject(UserField.create({ field_type: 'text' }));
},
destroy: function(f) {
var model = this.get('model'),
self = this;
// Only confirm if we already been saved
if (f.get('id')) {
bootbox.confirm(I18n.t("admin.user_fields.delete_confirm"), function(result) {
if (result) { self._performDestroy(f, model); }
});
} else {
self._performDestroy(f, model);
}
}
}
});

View File

@ -1,14 +1,7 @@
import ObjectController from 'discourse/controllers/object';
import CanCheckEmails from 'discourse/mixins/can-check-emails';
/**
A controller related to viewing a user in the admin section
@class AdminUserIndexController
@extends ObjectController
@namespace Discourse
@module Discourse
**/
export default ObjectController.extend({
export default ObjectController.extend(CanCheckEmails, {
editingTitle: false,
originalPrimaryGroupId: null,
availableGroups: null,
@ -22,6 +15,19 @@ export default ObjectController.extend({
return (!g.automatic && g.visible);
}),
userFields: function() {
var siteUserFields = this.site.get('user_fields'),
userFields = this.get('user_fields');
if (!Ember.empty(siteUserFields)) {
return siteUserFields.map(function(uf) {
var value = userFields ? userFields[uf.get('id').toString()] : null;
return {name: uf.get('name'), value: value};
});
}
return [];
}.property('user_fields.@each'),
actions: {
toggleTitleEdit: function() {
this.toggleProperty('editingTitle');

View File

@ -1,12 +1,3 @@
import ObjectController from 'discourse/controllers/object';
/**
The top-level controller for user pages in admin.
Ember assertion says that this class needs to be defined even if it's empty.
@class AdminUserController
@extends ObjectController
@namespace Discourse
@module Discourse
**/
export default ObjectController.extend();

View File

@ -13,10 +13,13 @@ export default Ember.ArrayController.extend(Discourse.Presence, {
content: null,
loading: false,
mustApproveUsers: Discourse.computed.setting('must_approve_users'),
queryNew: Em.computed.equal('query', 'new'),
queryPending: Em.computed.equal('query', 'pending'),
queryHasApproval: Em.computed.or('queryNew', 'queryPending'),
searchHint: function() { return I18n.t("search_hint"); }.property(),
/**
Triggered when the selectAll property is changed
@ -87,11 +90,11 @@ export default Ember.ArrayController.extend(Discourse.Presence, {
@method refreshUsers
**/
refreshUsers: function() {
refreshUsers: function(showEmails) {
var adminUsersListController = this;
adminUsersListController.set('loading', true);
Discourse.AdminUser.findAll(this.get('query'), { filter: this.get('username') }).then(function (result) {
Discourse.AdminUser.findAll(this.get('query'), { filter: this.get('username'), show_emails: showEmails }).then(function (result) {
adminUsersListController.set('content', result);
adminUsersListController.set('loading', false);
});
@ -137,6 +140,10 @@ export default Ember.ArrayController.extend(Discourse.Presence, {
bootbox.alert(message);
controller.refreshUsers();
});
},
showEmails: function() {
this.refreshUsers(true);
}
});

View File

@ -0,0 +1,3 @@
Em.Handlebars.helper('human-size', function(size) {
return new Handlebars.SafeString(I18n.toHumanSize(size));
});

View File

@ -164,6 +164,28 @@ Discourse.AdminUser = Discourse.User.extend({
this.set('trustLevel.id', this.get('originalTrustLevel'));
},
lockTrustLevel: function(locked) {
Discourse.ajax("/admin/users/" + this.id + "/trust_level_lock", {
type: 'PUT',
data: { locked: !!locked }
}).then(function() {
// succeeded
window.location.reload();
}, function(e) {
// failure
var error;
if (e.responseJSON && e.responseJSON.errors) {
error = e.responseJSON.errors[0];
}
error = error || I18n.t('admin.user.trust_level_change_failed', { error: "http: " + e.status + " - " + e.body });
bootbox.alert(error);
});
},
canLockTrustLevel: function(){
return this.get('trust_level') < 4;
}.property('trust_level'),
isSuspended: Em.computed.equal('suspended', true),
canSuspend: Em.computed.not('staff'),
@ -266,7 +288,7 @@ Discourse.AdminUser = Discourse.User.extend({
},
sendActivationEmail: function() {
Discourse.ajax('/users/' + this.get('username') + '/send_activation_email', {type: 'POST'}).then(function() {
Discourse.ajax('/users/action/send_activation_email', {data: {username: this.get('username')}, type: 'POST'}).then(function() {
// succeeded
bootbox.alert( I18n.t('admin.user.activation_email_sent') );
}, function(e) {
@ -307,9 +329,7 @@ Discourse.AdminUser = Discourse.User.extend({
data: formData
}).then(function(data) {
if (data.deleted) {
bootbox.alert(I18n.t("admin.user.deleted"), function() {
document.location = "/admin/users/list/active";
});
document.location = "/admin/users/list/active";
} else {
bootbox.alert(I18n.t("admin.user.delete_failed"));
if (data.user) {
@ -347,32 +367,47 @@ Discourse.AdminUser = Discourse.User.extend({
deleteAsSpammer: function(successCallback) {
var user = this;
var message = I18n.t('flagging.delete_confirm', {posts: user.get('post_count'), topics: user.get('topic_count'), email: user.get('email'), ip_address: user.get('ip_address')});
var buttons = [{
"label": I18n.t("composer.cancel"),
"class": "cancel-inline",
"link": true
}, {
"label": '<i class="fa fa-exclamation-triangle"></i> ' + I18n.t("flagging.yes_delete_spammer"),
"class": "btn btn-danger",
"callback": function() {
Discourse.ajax("/admin/users/" + user.get('id') + '.json', {
type: 'DELETE',
data: {delete_posts: true, block_email: true, block_urls: true, block_ip: true, context: window.location.pathname}
}).then(function(data) {
if (data.deleted) {
bootbox.alert(I18n.t("admin.user.deleted"), function() {
user.checkEmail().then(function() {
var data = {
posts: user.get('post_count'),
topics: user.get('topic_count'),
email: user.get('email') || I18n.t("flagging.hidden_email_address"),
ip_address: user.get('ip_address') || I18n.t("flagging.ip_address_missing")
};
var message = I18n.t('flagging.delete_confirm', data);
var buttons = [{
"label": I18n.t("composer.cancel"),
"class": "cancel-inline",
"link": true
}, {
"label": '<i class="fa fa-exclamation-triangle"></i> ' + I18n.t("flagging.yes_delete_spammer"),
"class": "btn btn-danger",
"callback": function() {
Discourse.ajax("/admin/users/" + user.get('id') + '.json', {
type: 'DELETE',
data: {
delete_posts: true,
block_email: true,
block_urls: true,
block_ip: true,
delete_as_spammer: true,
context: window.location.pathname
}
}).then(function(result) {
if (result.deleted) {
if (successCallback) successCallback();
});
} else {
} else {
bootbox.alert(I18n.t("admin.user.delete_failed"));
}
}, function() {
bootbox.alert(I18n.t("admin.user.delete_failed"));
}
}, function() {
bootbox.alert(I18n.t("admin.user.delete_failed"));
});
}
}];
bootbox.dialog(message, buttons, {"classes": "flagging-delete-spammer"});
});
}
}];
bootbox.dialog(message, buttons, {"classes": "flagging-delete-spammer"});
});
},
loadDetails: function() {
@ -385,11 +420,11 @@ Discourse.AdminUser = Discourse.User.extend({
});
},
leaderRequirements: function() {
if (this.get('leader_requirements')) {
return Discourse.LeaderRequirements.create(this.get('leader_requirements'));
tl3Requirements: function() {
if (this.get('tl3_requirements')) {
return Discourse.TL3Requirements.create(this.get('tl3_requirements'));
}
}.property('leader_requirements'),
}.property('tl3_requirements'),
suspendedBy: function() {
if (this.get('suspended_by')) {

View File

@ -1,16 +1,9 @@
/**
Data model for representing the status of backup/restore
@class BackupStatus
@extends Discourse.Model
@namespace Discourse
@module Discourse
**/
Discourse.BackupStatus = Discourse.Model.extend({
restoreDisabled: Em.computed.not("restoreEnabled"),
restoreEnabled: function() {
return Discourse.SiteSettings.allow_restore && !this.get("isOperationRunning");
}.property("isOperationRunning")
return this.get('allowRestore') && !this.get("isOperationRunning");
}.property("isOperationRunning", "allowRestore")
});

View File

@ -1,41 +0,0 @@
/**
A model for a git commit to the discourse repo, fetched from the github.com api.
@class GithubCommit
@extends Discourse.Model
@namespace Discourse
@module Discourse
**/
Discourse.GithubCommit = Discourse.Model.extend({
gravatarUrl: function(){
if( this.get('author') && this.get('author.gravatar_id') ){
return("https://www.gravatar.com/avatar/" + this.get('author.gravatar_id') + ".png?s=38&r=pg&d=identicon");
} else {
return "https://www.gravatar.com/avatar/b30fff48d257cdd17c4437afac19fd30.png?s=38&r=pg&d=identicon";
}
}.property("commit"),
commitUrl: function(){
return("https://github.com/discourse/discourse/commit/" + this.get('sha'));
}.property("sha"),
timeAgo: function() {
return moment(this.get('commit.committer.date')).relativeAge({format: 'medium', leaveAgo: true});
}.property("commit.committer.date")
});
Discourse.GithubCommit.reopenClass({
findAll: function() {
var result = Em.A();
Discourse.ajax( "https://api.github.com/repos/discourse/discourse/commits?callback=callback", {
dataType: 'jsonp',
type: 'get',
data: { per_page: 40 }
}).then(function (response) {
_.each(response.data,function(commit) {
result.pushObject( Discourse.GithubCommit.create(commit) );
});
});
return result;
}
});

View File

@ -1,4 +1,4 @@
Discourse.LeaderRequirements = Discourse.Model.extend({
Discourse.TL3Requirements = Discourse.Model.extend({
days_visited_percent: function() {
return ((this.get('days_visited') * 100) / this.get('time_period'));
}.property('days_visited', 'time_period'),
@ -18,7 +18,10 @@ Discourse.LeaderRequirements = Discourse.Model.extend({
flagged_posts: this.get('num_flagged_posts') <= this.get('max_flagged_posts'),
flagged_by_users: this.get('num_flagged_by_users') <= this.get('max_flagged_by_users'),
likes_given: this.get('num_likes_given') >= this.get('min_likes_given'),
likes_received: this.get('num_likes_received') >= this.get('min_likes_received')
likes_received: this.get('num_likes_received') >= this.get('min_likes_received'),
likes_received_days: this.get('num_likes_received_days') >= this.get('min_likes_received_days'),
likes_received_users: this.get('num_likes_received_users') >= this.get('min_likes_received_users'),
level_locked: this.get('trust_level_locked')
};
}.property('days_visited', 'min_days_visited',
'num_topics_replied_to', 'min_topics_replied_to',
@ -29,5 +32,9 @@ Discourse.LeaderRequirements = Discourse.Model.extend({
'posts_read_all_time', 'min_posts_read_all_time',
'num_flagged_by_users', 'max_flagged_by_users',
'num_likes_given', 'min_likes_given',
'num_likes_received', 'min_likes_received')
'num_likes_received', 'min_likes_received',
'num_likes_received', 'min_likes_received',
'num_likes_received_days', 'min_likes_received_days',
'num_likes_received_users', 'min_likes_received_users',
'trust_level_locked')
});

View File

@ -140,9 +140,12 @@ Discourse.Report = Discourse.Model.extend({
});
Discourse.Report.reopenClass({
find: function(type) {
var model = Discourse.Report.create({type: type});
Discourse.ajax("/admin/reports/" + type).then(function (json) {
find: function(type, startDate, endDate) {
return Discourse.ajax("/admin/reports/" + type, {data: {
start_date: startDate,
end_date: endDate
}}).then(function (json) {
// Add a percent field to each tuple
var maxY = 0;
json.report.data.forEach(function (row) {
@ -153,9 +156,9 @@ Discourse.Report.reopenClass({
row.percentage = Math.round((row.y / maxY) * 100);
});
}
var model = Discourse.Report.create({type: type});
model.setProperties(json.report);
model.set('loaded', true);
return model;
});
return(model);
}
});

View File

@ -1,39 +0,0 @@
/**
Our data model for interacting with custom site content
@class SiteContent
@extends Discourse.Model
@namespace Discourse
@module Discourse
**/
Discourse.SiteContent = Discourse.Model.extend({
markdown: Em.computed.equal('format', 'markdown'),
plainText: Em.computed.equal('format', 'plain'),
html: Em.computed.equal('format', 'html'),
css: Em.computed.equal('format', 'css'),
/**
Save the content
@method save
@return {jqXHR} a jQuery Promise object
**/
save: function() {
return Discourse.ajax("/admin/site_contents/" + this.get('content_type'), {
type: 'PUT',
data: {content: this.get('content')}
});
}
});
Discourse.SiteContent.reopenClass({
find: function(type) {
return Discourse.ajax("/admin/site_contents/" + type).then(function (data) {
return Discourse.SiteContent.create(data.site_content);
});
}
});

View File

@ -1,21 +0,0 @@
/**
Our data model that represents types of editing site content
@class SiteContentType
@extends Discourse.Model
@namespace Discourse
@module Discourse
**/
Discourse.SiteContentType = Discourse.Model.extend({});
Discourse.SiteContentType.reopenClass({
findAll: function() {
return Discourse.ajax("/admin/site_content_types").then(function(data) {
var contentTypes = Em.A();
data.forEach(function (ct) {
contentTypes.pushObject(Discourse.SiteContentType.create(ct));
});
return contentTypes;
});
}
});

View File

@ -9,11 +9,6 @@
Discourse.SiteCustomization = Discourse.Model.extend({
trackedProperties: ['enabled', 'name', 'stylesheet', 'header', 'mobile_stylesheet', 'mobile_header', 'override_default_style'],
init: function() {
this._super();
this.startTrackingChanges();
},
description: function() {
return "" + this.name + (this.enabled ? ' (*)' : '');
}.property('selected', 'name'),
@ -43,7 +38,7 @@ Discourse.SiteCustomization = Discourse.Model.extend({
return true;
});
this.set('originals', originals);
},
}.on('init'),
previewUrl: function() {
return "/?preview-style=" + (this.get('key'));
@ -103,15 +98,14 @@ var SiteCustomizations = Ember.ArrayProxy.extend({
Discourse.SiteCustomization.reopenClass({
findAll: function() {
var customizations = SiteCustomizations.create({ content: [], loading: true });
Discourse.ajax("/admin/site_customizations").then(function (data) {
return Discourse.ajax("/admin/site_customizations").then(function (data) {
var content = [];
if (data) {
_.each(data.site_customizations,function(c) {
customizations.pushObject(Discourse.SiteCustomization.create(c.site_customizations));
content = data.site_customizations.map(function(c) {
return Discourse.SiteCustomization.create(c);
});
}
customizations.set('loading', false);
return SiteCustomizations.create({ content: content });
});
return customizations;
}
});

View File

@ -0,0 +1,21 @@
Discourse.SiteText = Discourse.Model.extend({
markdown: Em.computed.equal('format', 'markdown'),
plainText: Em.computed.equal('format', 'plain'),
html: Em.computed.equal('format', 'html'),
css: Em.computed.equal('format', 'css'),
save: function() {
return Discourse.ajax("/admin/customize/site_text/" + this.get('text_type'), {
type: 'PUT',
data: {value: this.get('value')}
});
}
});
Discourse.SiteText.reopenClass({
find: function(type) {
return Discourse.ajax("/admin/customize/site_text/" + type).then(function (data) {
return Discourse.SiteText.create(data.site_text);
});
}
});

View File

@ -0,0 +1,11 @@
Discourse.SiteTextType = Discourse.Model.extend();
Discourse.SiteTextType.reopenClass({
findAll: function() {
return Discourse.ajax("/admin/customize/site_text_types").then(function(data) {
return data.map(function(ct) {
return Discourse.SiteTextType.create(ct);
});
});
}
});

View File

@ -17,6 +17,8 @@ Discourse.StaffActionLog = Discourse.Model.extend({
var formatted = "";
formatted += this.format('email', 'email');
formatted += this.format('admin.logs.ip_address', 'ip_address');
formatted += this.format('admin.logs.topic_id', 'topic_id');
formatted += this.format('admin.logs.post_id', 'post_id');
if (!this.get('useCustomModalForDetails')) {
formatted += this.format('admin.logs.staff_actions.new_value', 'new_value');
formatted += this.format('admin.logs.staff_actions.previous_value', 'previous_value');
@ -25,7 +27,7 @@ Discourse.StaffActionLog = Discourse.Model.extend({
if (this.get('details')) formatted += Handlebars.Utils.escapeExpression(this.get('details')) + '<br/>';
}
return formatted;
}.property('ip_address', 'email'),
}.property('ip_address', 'email', 'topic_id', 'post_id'),
format: function(label, propertyName) {
if (this.get(propertyName)) {

View File

@ -0,0 +1,54 @@
var _fieldTypes = [
Ember.Object.create({id: 'text', name: I18n.t('admin.user_fields.field_types.text') }),
Ember.Object.create({id: 'confirm', name: I18n.t('admin.user_fields.field_types.confirm') })
];
var UserField = Ember.Object.extend({
destroy: function() {
var self = this;
return new Ember.RSVP.Promise(function(resolve) {
var id = self.get('id');
if (id) {
return Discourse.ajax("/admin/customize/user_fields/" + id, { type: 'DELETE' }).then(function() {
resolve();
});
}
resolve();
});
},
save: function(attrs) {
var id = this.get('id');
if (!id) {
return Discourse.ajax("/admin/customize/user_fields", {
type: "POST",
data: { user_field: attrs }
});
} else {
return Discourse.ajax("/admin/customize/user_fields/" + id, {
type: "PUT",
data: { user_field: attrs }
});
}
}
});
UserField.reopenClass({
findAll: function() {
return Discourse.ajax("/admin/customize/user_fields").then(function(result) {
return result.user_fields.map(function(uf) {
return UserField.create(uf);
});
});
},
fieldTypes: function() {
return _fieldTypes;
},
fieldTypeById: function(id) {
return _fieldTypes.findBy('id', id);
}
});
export default UserField;

View File

@ -0,0 +1,52 @@
export default Ember.Route.extend({
serialize: function(m) {
return {badge_id: Em.get(m, 'id') || 'new'};
},
model: function(params) {
if (params.badge_id === "new") {
return Discourse.Badge.create({
name: I18n.t('admin.badges.new_badge')
});
}
return this.modelFor('adminBadges').findProperty('id', parseInt(params.badge_id));
},
actions: {
saveError: function(e) {
var msg = I18n.t("generic_error");
if (e.responseJSON && e.responseJSON.errors) {
msg = I18n.t("generic_error_with_reason", {error: e.responseJSON.errors.join('. ')});
}
bootbox.alert(msg);
},
editGroupings: function() {
var groupings = this.controllerFor('admin-badges').get('badgeGroupings');
Discourse.Route.showModal(this, 'admin_edit_badge_groupings', groupings);
},
preview: function(badge, explain) {
var self = this;
badge.set('preview_loading', true);
Discourse.ajax('/admin/badges/preview.json', {
method: 'post',
data: {
sql: badge.get('query'),
target_posts: !!badge.get('target_posts'),
trigger: badge.get('trigger'),
explain: explain
}
}).then(function(json) {
badge.set('preview_loading', false);
Discourse.Route.showModal(self, 'admin_badge_preview', json);
}).catch(function(error) {
badge.set('preview_loading', false);
Em.Logger.error(error);
bootbox.alert("Network error");
});
}
}
});

View File

@ -0,0 +1,28 @@
export default Discourse.Route.extend({
_json: null,
model: function() {
var self = this;
return Discourse.ajax('/admin/badges.json').then(function(json) {
self._json = json;
return Discourse.Badge.createFromJson(json);
});
},
setupController: function(controller, model) {
var json = this._json,
triggers = [];
_.each(json.admin_badges.triggers,function(v,k){
triggers.push({id: v, name: I18n.t('admin.badges.trigger_type.'+k)});
});
controller.setProperties({
badgeGroupings: json.badge_groupings,
badgeTypes: json.badge_types,
protectedSystemFields: json.admin_badges.protected_system_fields,
badgeTriggers: triggers,
model: model
});
}
});

View File

@ -11,7 +11,6 @@ export default Discourse.Route.extend({
setupController: function(c) {
this.fetchDashboardData(c);
this.fetchGithubCommits(c);
},
fetchDashboardData: function(c) {
@ -45,13 +44,6 @@ export default Discourse.Route.extend({
c.set('problemsFetchedAt', new Date());
c.loadProblems();
}
},
fetchGithubCommits: function(c) {
if( !c.get('commitsCheckedAt') || moment().subtract(1, 'hour').toDate() > c.get('commitsCheckedAt') ) {
c.set('commitsCheckedAt', new Date());
c.set('githubCommits', Discourse.GithubCommit.findAll());
}
}
});

View File

@ -0,0 +1,5 @@
export default Discourse.Route.extend({
model: function(params) {
return Discourse.SiteText.find(params.text_type);
}
});

View File

@ -0,0 +1,5 @@
export default Discourse.Route.extend({
model: function() {
return Discourse.SiteTextType.findAll();
}
});

View File

@ -0,0 +1,14 @@
import UserField from 'admin/models/user-field';
export default Discourse.Route.extend({
model: function() {
return UserField.findAll();
},
setupController: function(controller, model) {
controller.setProperties({
model: model,
fieldTypes: UserField.fieldTypes()
});
}
});

View File

@ -31,7 +31,8 @@ Discourse.AdminBackupsRoute = Discourse.Route.extend({
}).then(function (status) {
return Discourse.BackupStatus.create({
isOperationRunning: status.is_operation_running,
canRollback: status.can_rollback
canRollback: status.can_rollback,
allowRestore: status.allow_restore
});
});
},

View File

@ -1,23 +0,0 @@
Discourse.AdminBadgesRoute = Discourse.Route.extend({
setupController: function(controller) {
Discourse.ajax('/admin/badges.json').then(function(json){
controller.set('badgeGroupings', Em.A(json.badge_groupings));
controller.set('badgeTypes', json.badge_types);
controller.set('protectedSystemFields', json.admin_badges.protected_system_fields);
var triggers = [];
_.each(json.admin_badges.triggers,function(v,k){
triggers.push({id: v, name: I18n.t('admin.badges.trigger_type.'+k)});
});
controller.set('badgeTriggers', triggers);
controller.set('model', Discourse.Badge.createFromJson(json));
});
},
actions: {
editGroupings: function(model){
Discourse.Route.showModal(this, 'admin_edit_badge_groupings', model);
}
}
});

View File

@ -1,15 +1,5 @@
/**
Handles routes related to css/html customization
@class AdminCustomizeCssHtmlRoute
@extends Discourse.Route
@namespace Discourse
@module Discourse
**/
Discourse.AdminCustomizeCssHtmlRoute = Discourse.Route.extend({
model: function() {
return Discourse.SiteCustomization.findAll();
}
});

View File

@ -1,13 +1,5 @@
/**
Handles routes related to customization
@class AdminCustomizeIndexRoute
@extends Discourse.Route
@namespace Discourse
@module Discourse
**/
Discourse.AdminCustomizeIndexRoute = Discourse.Route.extend({
redirect: function() {
this.transitionTo('adminCustomize.colors');
beforeModel: function() {
this.replaceWith('adminCustomize.colors');
}
});

View File

@ -15,17 +15,6 @@ Discourse.AdminFlagsRouteType = Discourse.Route.extend({
adminFlagsController.set('query', this.get('filter'));
},
actions: {
/**
Deletes a user and all posts and topics created by that user.
@method deleteSpammer
**/
deleteSpammer: function (user) {
user.deleteAsSpammer(function() { window.location.reload(); });
}
}
});
Discourse.AdminFlagsActiveRoute = Discourse.AdminFlagsRouteType.extend({
@ -50,6 +39,3 @@ Discourse.AdminFlagsActiveRoute = Discourse.AdminFlagsRouteType.extend({
Discourse.AdminFlagsOldRoute = Discourse.AdminFlagsRouteType.extend({
filter: 'old'
});

View File

@ -1,4 +1,4 @@
Discourse.AdminGroupRoute = Em.Route.extend({
Discourse.AdminGroupRoute = Discourse.Route.extend({
model: function(params) {
var groups = this.modelFor('adminGroups'),

View File

@ -9,5 +9,13 @@
Discourse.AdminReportsRoute = Discourse.Route.extend({
model: function(params) {
return Discourse.Report.find(params.type);
},
setupController: function(controller, model) {
controller.setProperties({
model: model,
startDate: moment(model.get('start_date')).format('YYYY-MM-DD'),
endDate: moment(model.get('end_date')).format('YYYY-MM-DD')
});
}
});

View File

@ -1,17 +1,9 @@
/**
The base admin route
@class AdminRoute
@extends Discourse.Route
@namespace Discourse
@module Discourse
**/
Discourse.AdminRoute = Discourse.Route.extend({
renderTemplate: function() {
this.render('admin/templates/admin');
},
activate: function() {
Discourse.set('title', I18n.t('admin_title'));
titleToken: function() {
return I18n.t('admin_title');
}
});

View File

@ -1,9 +1,3 @@
/**
Builds the routes for the admin section
@method buildRoutes
@for Discourse.AdminRoute
**/
Discourse.Route.buildRoutes(function() {
this.resource('admin', function() {
this.route('dashboard', { path: '/' });
@ -11,10 +5,6 @@ Discourse.Route.buildRoutes(function() {
this.resource('adminSiteSettingsCategory', { path: 'category/:category_id'} );
});
this.resource('adminSiteContents', { path: '/site_contents' }, function() {
this.resource('adminSiteContentEdit', {path: '/:content_type'});
});
this.resource('adminEmail', { path: '/email'}, function() {
this.route('all');
this.route('sent');
@ -25,6 +15,11 @@ Discourse.Route.buildRoutes(function() {
this.resource('adminCustomize', { path: '/customize' } ,function() {
this.route('colors');
this.route('css_html');
this.resource('adminSiteText', { path: '/site_text' }, function() {
this.route('edit', {path: '/:text_type'});
});
this.resource('adminUserFields', { path: '/user_fields' }, function() {
});
});
this.route('api');
@ -53,7 +48,7 @@ Discourse.Route.buildRoutes(function() {
this.resource('adminUsers', { path: '/users' }, function() {
this.resource('adminUser', { path: '/:username' }, function() {
this.route('badges');
this.route('leaderRequirements', { path: '/leader_requirements' });
this.route('tl3Requirements', { path: '/tl3_requirements' });
});
this.resource('adminUsersList', { path: '/list' }, function() {
_.each(['active', 'new', 'pending', 'admins', 'moderators', 'blocked', 'suspended',
@ -63,7 +58,9 @@ Discourse.Route.buildRoutes(function() {
});
});
this.route('badges');
this.resource('adminBadges', { path: '/badges' }, function() {
this.route('show', { path: '/:badge_id' });
});
});
});

View File

@ -1,48 +0,0 @@
/**
Allows users to customize site content
@class AdminSiteContentEditRoute
@extends Discourse.Route
@namespace Discourse
@module Discourse
**/
Discourse.AdminSiteContentEditRoute = Discourse.Route.extend({
serialize: function(model) {
return {content_type: model.get('content_type')};
},
model: function(params) {
var list = Discourse.SiteContentType.findAll();
return list.then(function(items) {
return items.findProperty("content_type", params.content_type);
});
},
renderTemplate: function() {
this.render('admin/templates/site_content_edit', {into: 'admin/templates/site_contents'});
},
deactivate: function() {
this._super();
this.render('admin/templates/site_contents_empty', {into: 'admin/templates/site_contents'});
},
setupController: function(controller, model) {
controller.set('loaded', false);
controller.setProperties({
model: model,
saving: false,
saved: false
});
Discourse.SiteContent.find(model.get('content_type')).then(function (sc) {
controller.set('content', sc);
controller.set('loaded', true);
});
}
});

View File

@ -1,24 +0,0 @@
/**
Allows users to customize site content
@class AdminSiteContentsRoute
@extends Discourse.Route
@namespace Discourse
@module Discourse
**/
Discourse.AdminSiteContentsRoute = Discourse.Route.extend({
model: function() {
return Discourse.SiteContentType.findAll();
},
renderTemplate: function() {
this.render('admin/templates/site_contents', {into: 'admin/templates/admin'});
this.render('admin/templates/site_contents_empty', {into: 'admin/templates/site_contents'});
},
setupController: function(controller, model) {
controller.set('model', model);
}
});

View File

@ -7,8 +7,8 @@
@namespace Discourse
@module Discourse
**/
Discourse.AdminUserLeaderRequirementsRoute = Discourse.Route.extend({
Discourse.AdminUserTl3RequirementsRoute = Discourse.Route.extend({
model: function() {
return this.controllerFor('adminUser').get('model');
return this.modelFor('adminUser');
}
});

View File

@ -1,5 +1,5 @@
<div class="container">
{{Discourse.globalNotice}}
{{global-notice}}
<div class="row">
<div class="full-width">
@ -7,11 +7,10 @@
<li>{{#link-to 'admin.dashboard'}}{{i18n admin.dashboard.title}}{{/link-to}}</li>
{{#if currentUser.admin}}
<li>{{#link-to 'adminSiteSettings'}}{{i18n admin.site_settings.title}}{{/link-to}}</li>
<li>{{#link-to 'adminSiteContents'}}{{i18n admin.site_content.title}}{{/link-to}}</li>
{{/if}}
<li>{{#link-to 'adminUsersList'}}{{i18n admin.users.title}}{{/link-to}}</li>
{{#if showBadges}}
<li>{{#link-to 'admin.badges'}}{{i18n admin.badges.title}}{{/link-to}}</li>
<li>{{#link-to 'adminBadges.index'}}{{i18n admin.badges.title}}{{/link-to}}</li>
{{/if}}
{{#if currentUser.admin}}
<li>{{#link-to 'adminGroups.index'}}{{i18n admin.groups.title}}{{/link-to}}</li>
@ -20,7 +19,7 @@
<li>{{#link-to 'adminFlags'}}{{i18n admin.flags.title}}{{/link-to}}</li>
<li>{{#link-to 'adminLogs'}}{{i18n admin.logs.title}}{{/link-to}}</li>
{{#if currentUser.admin}}
<li>{{#link-to 'adminCustomize'}}{{i18n admin.customize.title}}{{/link-to}}</li>
<li>{{#link-to 'adminCustomize.colors'}}{{i18n admin.customize.title}}{{/link-to}}</li>
<li>{{#link-to 'admin.api'}}{{i18n admin.api.title}}{{/link-to}}</li>
<li>{{#link-to 'admin.backups'}}{{i18n admin.backups.title}}{{/link-to}}</li>
{{/if}}

View File

@ -18,8 +18,8 @@
{{/if}}
</td>
<td>
<button class='btn' {{action regenerateKey this}}><i class="fa fa-undo"></i>{{i18n admin.api.regenerate}}</button>
<button class='btn' {{action revokeKey this}}><i class="fa fa-times"></i>{{i18n admin.api.revoke}}</button>
<button class='btn' {{action "regenerateKey" this}}><i class="fa fa-undo"></i>{{i18n admin.api.regenerate}}</button>
<button class='btn' {{action "revokeKey" this}}><i class="fa fa-times"></i>{{i18n admin.api.revoke}}</button>
</td>
</tr>
{{/each}}
@ -29,5 +29,5 @@
{{/if}}
{{#unless hasMasterKey}}
<button class='btn' {{action generateMasterKey}}><i class="fa fa-key"></i>{{i18n admin.api.generate_master}}</button>
<button class='btn' {{action "generateMasterKey"}}><i class="fa fa-key"></i>{{i18n admin.api.generate_master}}</button>
{{/unless }}

View File

@ -0,0 +1,22 @@
<div class="admin-controls">
<div class="span15">
<ul class="nav nav-pills">
<li>{{#link-to "admin.backups.index"}}{{i18n admin.backups.menu.backups}}{{/link-to}}</li>
<li>{{#link-to "admin.backups.logs"}}{{i18n admin.backups.menu.logs}}{{/link-to}}</li>
</ul>
</div>
<div class="pull-right">
{{#if canRollback}}
<button {{action "rollback"}} class="btn btn-rollback" title="{{i18n admin.backups.operations.rollback.title}}" {{bind-attr disabled="rollbackDisabled"}}><i class="fa fa-ambulance fa-flip-horizontal"></i>{{i18n admin.backups.operations.rollback.text}}</button>
{{/if}}
{{#if isOperationRunning}}
<button {{action "cancelOperation"}} class="btn btn-danger" title="{{i18n admin.backups.operations.cancel.title}}"><i class="fa fa-times"></i>{{i18n admin.backups.operations.cancel.text}}</button>
{{else}}
<button {{action "startBackup"}} class="btn btn-primary" title="{{i18n admin.backups.operations.backup.title}}"><i class="fa fa-rocket"></i>{{i18n admin.backups.operations.backup.text}}</button>
{{/if}}
</div>
</div>
<div class="admin-container">
{{outlet}}
</div>

View File

@ -1,22 +0,0 @@
<div class="admin-controls">
<div class="span15">
<ul class="nav nav-pills">
<li>{{#link-to "admin.backups.index"}}{{i18n admin.backups.menu.backups}}{{/link-to}}</li>
<li>{{#link-to "admin.backups.logs"}}{{i18n admin.backups.menu.logs}}{{/link-to}}</li>
</ul>
</div>
<div class="pull-right">
{{#if canRollback}}
<button {{action rollback}} class="btn btn-rollback" title="{{i18n admin.backups.operations.rollback.title}}" {{bind-attr disabled="rollbackDisabled"}}><i class="fa fa-ambulance fa-flip-horizontal"></i>{{i18n admin.backups.operations.rollback.text}}</button>
{{/if}}
{{#if isOperationRunning}}
<button {{action cancelOperation}} class="btn btn-danger" title="{{i18n admin.backups.operations.cancel.title}}"><i class="fa fa-times"></i>{{i18n admin.backups.operations.cancel.text}}</button>
{{else}}
<button {{action startBackup}} class="btn btn-primary" title="{{i18n admin.backups.operations.backup.title}}"><i class="fa fa-rocket"></i>{{i18n admin.backups.operations.backup.text}}</button>
{{/if}}
</div>
</div>
<div class="admin-container">
{{outlet}}
</div>

View File

@ -5,7 +5,7 @@
<th>
<div class="pull-right">
{{resumable-upload target="/admin/backups/upload" success="uploadSuccess" error="uploadError" uploadText=uploadText}}
<button {{action toggleReadOnlyMode}} class="btn" {{bind-attr disabled="readOnlyModeDisabled" title="readOnlyModeTitle"}}><i class="fa fa-eye"></i>{{readOnlyModeText}}</button>
<button {{action "toggleReadOnlyMode"}} class="btn" {{bind-attr disabled="readOnlyModeDisabled" title="readOnlyModeTitle"}}><i class="fa fa-eye"></i>{{readOnlyModeText}}</button>
</div>
</th>
</tr>
@ -16,8 +16,8 @@
<td>
<div class="pull-right">
<a {{bind-attr href="backup.link"}} class="btn download" title="{{i18n admin.backups.operations.download.title}}"><i class="fa fa-download"></i>{{i18n admin.backups.operations.download.text}}</a>
<button {{action destroyBackup backup}} class="btn btn-danger" {{bind-attr disabled="destroyDisabled" title="destroyTitle"}}><i class="fa fa-trash-o"></i></button>
<button {{action startRestore backup}} class="btn" {{bind-attr disabled="restoreDisabled" title="restoreTitle"}}><i class="fa fa-play"></i>{{i18n admin.backups.operations.restore.text}}</button>
<button {{action "destroyBackup" backup}} class="btn btn-danger no-text" {{bind-attr disabled="destroyDisabled" title="destroyTitle"}}><i class="fa fa-trash-o"></i></button>
<button {{action "startRestore" backup}} class="btn" {{bind-attr disabled="restoreDisabled" title="restoreTitle"}}><i class="fa fa-play"></i>{{i18n admin.backups.operations.restore.text}}</button>
</div>
</td>
</tr>

View File

@ -0,0 +1,9 @@
<div class='span13'>
<p>{{i18n admin.badges.none_selected}}</p>
<div>
{{#link-to 'adminBadges.show' 'new' class="btn"}}
{{fa-icon "plus"}} {{i18n admin.badges.new}}
{{/link-to}}
</div>
</div>

View File

@ -0,0 +1,146 @@
<div class='current-badge span13'>
<form class="form-horizontal">
<div>
<label for="name">{{i18n admin.badges.name}}</label>
{{input type="text" name="name" value=buffered.name}}
</div>
{{#if showDisplayName}}
<div>
<strong>{{i18n admin.badges.display_name}}</strong>
{{buffered.displayName}}
</div>
{{/if}}
<div>
<label for="name">{{i18n admin.badges.icon}}</label>
{{input type="text" name="name" value=buffered.icon}}
<p class='help'>{{i18n admin.badges.icon_help}}</p>
</div>
<div>
<label for="name">{{i18n admin.badges.image}}</label>
{{input type="text" name="name" value=buffered.image}}
<p class='help'>{{i18n admin.badges.icon_help}}</p>
</div>
<div>
<label for="badge_type_id">{{i18n admin.badges.badge_type}}</label>
{{view Ember.Select name="badge_type_id"
value=buffered.badge_type_id
content=badgeTypes
optionValuePath="content.id"
optionLabelPath="content.name"
disabled=readOnly}}
</div>
<div>
<label for="badge_grouping_id">{{i18n admin.badges.badge_grouping}}</label>
{{view Ember.Select name="badge_grouping_id"
value=buffered.badge_grouping_id
content=badgeGroupings
optionValuePath="content.id"
optionLabelPath="content.name"}}
&nbsp;<button {{action "editGroupings"}} class='btn'>{{fa-icon 'pencil'}}</button>
</div>
<div>
<label for="description">{{i18n admin.badges.description}}</label>
{{#if canEditDescription}}
{{textarea name="description" value=buffered.description}}
{{else}}
{{textarea name="description" value=buffered.displayDescription disabled=true}}
{{/if}}
</div>
<div>
<label for="query">{{i18n admin.badges.query}}</label>
{{textarea name="query" value=buffered.query disabled=readOnly}}
</div>
{{#if hasQuery}}
<a href {{action "preview" buffered "false"}}>{{i18n admin.badges.preview.link_text}}</a>
|
<a href {{action "preview" buffered "true"}}>{{i18n admin.badges.preview.plan_text}}</a>
{{#if preview_loading}}
{{i18n loading}}...
{{/if}}
<div>
<label>
{{input type="checkbox" checked=buffered.auto_revoke disabled=readOnly}}
{{i18n admin.badges.auto_revoke}}
</label>
</div>
<div>
<label>
{{input type="checkbox" checked=buffered.target_posts disabled=readOnly}}
{{i18n admin.badges.target_posts}}
</label>
</div>
<div>
<label for="trigger">{{i18n admin.badges.trigger}}</label>
{{view Ember.Select name="trigger"
value=buffered.trigger
content=badgeTriggers
optionValuePath="content.id"
optionLabelPath="content.name"
disabled=readOnly}}
</div>
{{/if}}
<div>
<label>
{{input type="checkbox" checked=buffered.allow_title}}
{{i18n admin.badges.allow_title}}
</label>
</div>
<div>
<label>
{{input type="checkbox" checked=buffered.multiple_grant disabled=readOnly}}
{{i18n admin.badges.multiple_grant}}
</label>
</div>
<div>
<label>
{{input type="checkbox" checked=buffered.listable disabled=readOnly}}
{{i18n admin.badges.listable}}
</label>
</div>
<div>
<label>
{{input type="checkbox" checked=buffered.show_posts disabled=readOnly}}
{{i18n admin.badges.show_posts}}
</label>
</div>
<div>
<label>
{{input type="checkbox" checked=buffered.enabled}}
{{i18n admin.badges.enabled}}
</label>
</div>
<div class='buttons'>
<button {{action "save"}} {{bind-attr disabled=saving}} class='btn btn-primary'>{{i18n admin.badges.save}}</button>
<span class='saving'>{{savingStatus}}</span>
{{#unless readOnly}}
<a {{action "destroy"}} class='delete-link'>{{i18n admin.badges.delete}}</a>
{{/unless}}
</div>
</form>
</div>
{{#if grant_count}}
<div class="span13 current-badge-actions">
<div>
{{#link-to 'badges.show' this}}{{i18n badges.granted count=grant_count}}{{/link-to}}
</div>
</div>
{{/if}}

View File

@ -0,0 +1,25 @@
<div class="badges">
<div class='content-list span6'>
<h3>{{i18n admin.badges.title}}</h3>
<ul>
{{#each}}
<li>
{{#link-to 'adminBadges.show' id}}
{{badge-button badge=this}}
{{#if newBadge}}
<span class="list-badge">{{i18n filters.new.lower_title}}</span>
{{/if}}
{{/link-to}}
</li>
{{/each}}
</ul>
{{#link-to 'adminBadges.show' 'new' class="btn"}}
{{fa-icon "plus"}} {{i18n admin.badges.new}}
{{/link-to}}
<br>
<br>
</div>
{{outlet}}
</div>

View File

@ -1,161 +0,0 @@
<div class="badges">
<div class='content-list span6'>
<h3>{{i18n admin.badges.title}}</h3>
<ul>
{{#each}}
<li>
<a {{action selectBadge this}} {{bind-attr class="selected:active"}}>
<span {{bind-attr class=":user-badge badgeTypeClassName" data-badge-name="name" title="displayDescription"}}>
<i {{bind-attr class=":fa icon"}}></i>
{{displayName}}
</span>
{{#if newBadge}}
<span class="list-badge">{{i18n filters.new.lower_title}}</span>
{{/if}}
</a>
</li>
{{/each}}
</ul>
<button {{action createNewBadge}} {{bind-attr disabled=newBadgeExists}} class='btn'><i class="fa fa-plus"></i>{{i18n admin.badges.new}}</button>
</div>
{{#if selectedItem}}
{{#with selectedItem controller='adminBadge'}}
<div class='current-badge span13'>
<form class="form-horizontal">
<div>
<label for="name">{{i18n admin.badges.name}}</label>
{{input type="text" name="name" value=name}}
</div>
{{#if showDisplayName}}
<div>
<strong>{{i18n admin.badges.display_name}}</strong>
{{displayName}}
</div>
{{/if}}
<div>
<label for="name">{{i18n admin.badges.icon}}</label>
{{input type="text" name="name" value=icon}}
</div>
<div>
<label for="badge_type_id">{{i18n admin.badges.badge_type}}</label>
{{view Ember.Select name="badge_type_id" value=badge_type_id
content=controller.badgeTypes
optionValuePath="content.id"
optionLabelPath="content.name"
disabled=readOnly}}
</div>
<div>
<label for="badge_grouping_id">{{i18n admin.badges.badge_grouping}}</label>
{{view Ember.Select name="badge_grouping_id" value=badge_grouping_id
content=controller.badgeGroupings
optionValuePath="content.id"
optionLabelPath="content.name"}}
&nbsp;<button {{action editGroupings controller.badgeGroupings}}><i class="fa fa-pencil"></i></button>
</div>
<div>
<label for="description">{{i18n admin.badges.description}}</label>
{{#if controller.canEditDescription}}
{{textarea name="description" value=description}}
{{else}}
{{textarea name="description" value=displayDescription disabled=true}}
{{/if}}
</div>
<div>
<label for="query">{{i18n admin.badges.query}}</label>
{{textarea name="query" value=query disabled=readOnly}}
</div>
{{#if hasQuery}}
<a href="/admin/badges/preview" {{action preview this}}>{{i18n admin.badges.preview}}</a>
<div>
<span>
{{input type="checkbox" checked=auto_revoke disabled=readOnly}}
{{i18n admin.badges.auto_revoke}}
</span>
</div>
<div>
<span>
{{input type="checkbox" checked=target_posts disabled=readOnly}}
{{i18n admin.badges.target_posts}}
</span>
</div>
<div>
<label for="trigger">{{i18n admin.badges.trigger}}</label>
{{view Ember.Select name="trigger" value=trigger
content=controller.badgeTriggers
optionValuePath="content.id"
optionLabelPath="content.name"
disabled=readOnly}}
</div>
{{/if}}
<div>
<span>
{{input type="checkbox" checked=allow_title}}
{{i18n admin.badges.allow_title}}
</span>
</div>
<div>
<span>
{{input type="checkbox" checked=multiple_grant disabled=readOnly}}
{{i18n admin.badges.multiple_grant}}
</span>
</div>
<div>
<span>
{{input type="checkbox" checked=listable disabled=readOnly}}
{{i18n admin.badges.listable}}
</span>
</div>
<div>
<span>
{{input type="checkbox" checked=show_posts disabled=readOnly}}
{{i18n admin.badges.show_posts}}
</span>
</div>
<div>
<span>
{{input type="checkbox" checked=enabled}}
{{i18n admin.badges.enabled}}
</span>
</div>
<div class='buttons'>
<button {{action save}} {{bind-attr disabled=controller.disableSave}} class='btn btn-primary'>{{i18n admin.badges.save}}</button>
<span class='saving'>{{savingStatus}}</span>
{{#unless readOnly}}
<a {{action destroy}} class='delete-link'>{{i18n admin.badges.delete}}</a>
{{/unless}}
</div>
</form>
</div>
{{#if grant_count}}
<div class="span13 current-badge-actions">
<div>
{{#link-to 'badges.show' this}}{{i18n badges.granted count=grant_count}}{{/link-to}}
</div>
</div>
{{/if}}
{{/with}}
{{/if}}
</div>

View File

@ -1,21 +0,0 @@
<div class="commits-widget">
<div class="header" {{action "goToGithub"}}>
<h1>
<i class="fa fa-github"></i>
{{i18n admin.commits.latest_changes}}
</h1>
</div>
<ul class="commits-list">
{{#each controller}}
<li>
<div class="left">
<img {{bind-attr src="gravatarUrl"}}>
</div>
<div class="right">
<span class="commit-message"><a {{bind-attr href="commitUrl"}} target="_blank">{{ commit.message }}</a></span><br/>
<span class="commit-meta">{{i18n admin.commits.by}} <span class="committer-name">{{ commit.author.name }}</span> - <span class="commit-time">{{{ timeAgo }}}</span></span>
</div>
</li>
{{/each}}
</ul>
</div>

View File

@ -3,6 +3,8 @@
<ul class="nav nav-pills">
<li>{{#link-to 'adminCustomize.colors'}}{{i18n admin.customize.colors.title}}{{/link-to}}</li>
<li>{{#link-to 'adminCustomize.css_html'}}{{i18n admin.customize.css_html.title}}{{/link-to}}</li>
<li>{{#link-to 'adminSiteText'}}{{i18n admin.site_text.title}}{{/link-to}}</li>
<li>{{#link-to 'adminUserFields'}}{{i18n admin.user_fields.title}}{{/link-to}}</li>
</ul>
</div>
</div>

View File

@ -3,11 +3,11 @@
<ul>
{{#each model}}
{{#unless is_base}}
<li><a {{action selectColorScheme this}} {{bind-attr class="selected:active"}}>{{description}}</a></li>
<li><a {{action "selectColorScheme" this}} {{bind-attr class="selected:active"}}>{{description}}</a></li>
{{/unless}}
{{/each}}
</ul>
<button {{action newColorScheme}} class='btn'><i class="fa fa-plus"></i>{{i18n admin.customize.new}}</button>
<button {{action "newColorScheme"}} class='btn'><i class="fa fa-plus"></i>{{i18n admin.customize.new}}</button>
</div>
{{#if selectedItem}}
@ -17,16 +17,16 @@
<h1>{{text-field class="style-name" value=name}}</h1>
<div class="controls">
<button {{action save}} {{bind-attr disabled="disableSave"}} class='btn'>{{i18n admin.customize.save}}</button>
<button {{action toggleEnabled}} {{bind-attr disabled="disableEnable"}} class="btn">
<button {{action "save"}} {{bind-attr disabled="disableSave"}} class='btn'>{{i18n admin.customize.save}}</button>
<button {{action "toggleEnabled"}} {{bind-attr disabled="disableEnable"}} class="btn">
{{#if enabled}}
{{i18n disable}}
{{else}}
{{i18n enable}}
{{/if}}
</button>
<button {{action copy this}} class='btn'><i class="fa fa-copy"></i> {{i18n admin.customize.copy}}</button>
<button {{action destroy}} class='btn btn-danger'><i class="fa fa-trash-o"></i> {{i18n admin.customize.delete}}</button>
<button {{action "copy" this}} class='btn'><i class="fa fa-copy"></i> {{i18n admin.customize.copy}}</button>
<button {{action "destroy"}} class='btn btn-danger'><i class="fa fa-trash-o"></i> {{i18n admin.customize.delete}}</button>
<span {{bind-attr class=":saving savingStatus::hidden" }}>{{savingStatus}}</span>
</div>
{{/with}}
@ -61,8 +61,8 @@
</td>
<td class="hex">{{color-input hexValue=hex brightnessValue=brightness valid=valid}}</td>
<td class="actions">
<button {{bind-attr class=":btn :revert savedIsOverriden::invisible"}} {{action revert this}} title="{{i18n admin.customize.colors.revert_title}}">{{i18n revert}}</button>
<button {{bind-attr class=":btn :undo changed::invisible"}} {{action undo this}} title="{{i18n admin.customize.colors.undo_title}}">{{i18n undo}}</button>
<button {{bind-attr class=":btn :revert savedIsOverriden::invisible"}} {{action "revert" this}} title="{{i18n admin.customize.colors.revert_title}}">{{i18n revert}}</button>
<button {{bind-attr class=":btn :undo changed::invisible"}} {{action "undo" this}} title="{{i18n admin.customize.colors.undo_title}}">{{i18n undo}}</button>
</td>
</tr>
{{/each}}
@ -77,4 +77,4 @@
<p class="about">{{i18n admin.customize.colors.about}}</p>
{{/if}}
<div class="clearfix"></div>
<div class="clearfix"></div>

View File

@ -2,10 +2,10 @@
<h3>{{i18n admin.customize.css_html.long_title}}</h3>
<ul>
{{#each model}}
<li><a {{action selectStyle this}} {{bind-attr class="this.selected:active"}}>{{this.description}}</a></li>
<li><a {{action "selectStyle" this}} {{bind-attr class="this.selected:active"}}>{{this.description}}</a></li>
{{/each}}
</ul>
<button {{action newCustomization}} class='btn'><i class="fa fa-plus"></i>{{i18n admin.customize.new}}</button>
<button {{action "newCustomization"}} class='btn'><i class="fa fa-plus"></i>{{i18n admin.customize.new}}</button>
</div>
@ -17,16 +17,16 @@
<div class='admin-controls'>
<ul class="nav nav-pills">
<li>
<a {{bind-attr class="view.stylesheetActive:active"}}{{action selectStylesheet href="true" target="view"}}>{{i18n admin.customize.css}}</a>
<a {{bind-attr class="view.stylesheetActive:active"}}{{action "selectStylesheet" href="true" target="view"}}>{{i18n admin.customize.css}}</a>
</li>
<li>
<a {{bind-attr class="view.headerActive:active"}}{{action selectHeader href="true" target="view"}}>{{i18n admin.customize.header}}</a>
<a {{bind-attr class="view.headerActive:active"}}{{action "selectHeader" href="true" target="view"}}>{{i18n admin.customize.header}}</a>
</li>
<li>
<a {{bind-attr class="view.mobileStylesheetActive:active"}}{{action selectMobileStylesheet href="true" target="view"}}>{{i18n admin.customize.mobile_css}}</a>
<a {{bind-attr class="view.mobileStylesheetActive:active"}}{{action "selectMobileStylesheet" href="true" target="view"}}>{{i18n admin.customize.mobile_css}}</a>
</li>
<li>
<a {{bind-attr class="view.mobileHeaderActive:active"}}{{action selectMobileHeader href="true" target="view"}}>{{i18n admin.customize.mobile_header}}</a>
<a {{bind-attr class="view.mobileHeaderActive:active"}}{{action "selectMobileHeader" href="true" target="view"}}>{{i18n admin.customize.mobile_header}}</a>
</li>
</ul>
</div>
@ -60,9 +60,9 @@
</div>
<div class='buttons'>
<button {{action save}} {{bind-attr disabled="selectedItem.disableSave"}} class='btn'>{{i18n admin.customize.save}}</button>
<button {{action "save"}} {{bind-attr disabled="selectedItem.disableSave"}} class='btn'>{{i18n admin.customize.save}}</button>
<span class='saving'>{{selectedItem.savingStatus}}</span>
<a {{action destroy}} class='delete-link'>{{i18n admin.customize.delete}}</a>
<a {{action "destroy"}} class='delete-link'>{{i18n admin.customize.delete}}</a>
</div>
</div>

View File

@ -1,39 +1,5 @@
<div class="dashboard-left">
{{#if foundProblems}}
<div class="dashboard-stats detected-problems">
<div class="look-here"><i class="fa fa-exclamation-triangle"></i></div>
<div class="problem-messages">
<p {{bind-attr class="loadingProblems:invisible"}}>
{{i18n admin.dashboard.problems_found}}
<ul {{bind-attr class="loadingProblems:invisible"}}>
{{#each problem in problems}}
<li>{{{problem}}}</li>
{{/each}}
</ul>
</p>
<p class="actions">
<small>{{i18n admin.dashboard.last_checked}}: {{problemsTimestamp}}</small>
<button {{action refreshProblems}} class="btn btn-small"><i class="fa fa-refresh"></i>{{i18n admin.dashboard.refresh_problems}}</button>
</p>
</div>
<div class="clearfix"></div>
</div>
{{else}}
{{#if thereWereProblems}}
<div class="dashboard-stats detected-problems">
<div class="look-here">&nbsp;</div>
<div class="problem-messages">
<p>
{{i18n admin.dashboard.no_problems}}
<button {{action refreshProblems}} class="btn btn-small"><i class="fa fa-refresh"></i>{{i18n admin.dashboard.refresh_problems}}</button>
</p>
</div>
<div class="clearfix"></div>
</div>
{{/if}}
{{/if}}
{{#if Discourse.SiteSettings.version_checks}}
{{#if showVersionChecks}}
{{partial 'admin/templates/version_checks'}}
{{/if}}
@ -138,7 +104,40 @@
</div>
<div class="dashboard-right">
{{ render 'admin/templates/commits' githubCommits }}
{{#if foundProblems}}
<div class="dashboard-stats detected-problems">
<div class="look-here"><i class="fa fa-exclamation-triangle"></i></div>
<div class="problem-messages">
<p {{bind-attr class="loadingProblems:invisible"}}>
{{i18n admin.dashboard.problems_found}}
<ul {{bind-attr class="loadingProblems:invisible"}}>
{{#each problem in problems}}
<li>{{{problem}}}</li>
{{/each}}
</ul>
</p>
<p class="actions">
<small>{{i18n admin.dashboard.last_checked}}: {{problemsTimestamp}}</small>
<button {{action "refreshProblems"}} class="btn btn-small"><i class="fa fa-refresh"></i>{{i18n admin.dashboard.refresh_problems}}</button>
</p>
</div>
<div class="clearfix"></div>
</div>
{{else}}
{{#if thereWereProblems}}
<div class="dashboard-stats detected-problems">
<div class="look-here">&nbsp;</div>
<div class="problem-messages">
<p>
{{i18n admin.dashboard.no_problems}}
<button {{action "refreshProblems"}} class="btn btn-small"><i class="fa fa-refresh"></i>{{i18n admin.dashboard.refresh_problems}}</button>
</p>
</div>
<div class="clearfix"></div>
</div>
{{/if}}
{{/if}}
<div class="dashboard-stats">
<table class="table table-condensed table-hover">

View File

@ -19,7 +19,7 @@
{{#each model}}
<tr>
<td>{{date created_at}}</td>
<td>{{format-date created_at}}</td>
<td>
{{#if user}}
{{#link-to 'adminUser' user}}{{avatar user imageSize="tiny"}}{{/link-to}}

View File

@ -20,7 +20,7 @@
{{text-field value=testEmailAddress placeholderKey="admin.email.test_email_address"}}
</div>
<div class='span10 controls'>
<button class='btn btn-primary' {{action sendTestEmail}} {{bind-attr disabled="sendTestEmailDisabled"}}>{{i18n admin.email.send_test}}</button>
<button class='btn btn-primary' {{action "sendTestEmail"}} {{bind-attr disabled="sendTestEmailDisabled"}}>{{i18n admin.email.send_test}}</button>
{{#if sentTestEmail}}<span class='result-message'>{{i18n admin.email.sent_test}}</span>{{/if}}
</div>
{{/if}}

View File

@ -6,20 +6,20 @@
{{input type="date" value=lastSeen id="last-seen"}}
</div>
<div>
<button class='btn' {{action refresh}}>{{i18n admin.email.refresh}}</button>
<button class='btn' {{action "refresh"}}>{{i18n admin.email.refresh}}</button>
</div>
<div class="span7 toggle">
<label>{{i18n admin.email.format}}</label>
{{#if showHtml}}
<span>{{i18n admin.email.html}}</span> | <a href='#' {{action toggleShowHtml}}>{{i18n admin.email.text}}</a>
<span>{{i18n admin.email.html}}</span> | <a href='#' {{action "toggleShowHtml"}}>{{i18n admin.email.text}}</a>
{{else}}
<a href='#' {{action toggleShowHtml}}>{{i18n admin.email.html}}</a> | <span>{{i18n admin.email.text}}</span>
<a href='#' {{action "toggleShowHtml"}}>{{i18n admin.email.html}}</a> | <span>{{i18n admin.email.text}}</span>
{{/if}}
</div>
</div>
{{#if loading}}
<div class='admin-loading'>{{i18n loading}}</div>
{{loading-spinner}}
{{else}}
{{#if showHtml}}
{{{html_content}}}

View File

@ -19,7 +19,7 @@
{{#each model}}
<tr>
<td>{{date created_at}}</td>
<td>{{format-date created_at}}</td>
<td>
{{#if user}}
{{#link-to 'adminUser' user}}{{avatar user imageSize="tiny"}}{{/link-to}}

View File

@ -19,7 +19,7 @@
{{#each model}}
<tr>
<td>{{date created_at}}</td>
<td>{{format-date created_at}}</td>
<td>
{{#if user}}
{{#link-to 'adminUser' user}}{{avatar user imageSize="tiny"}}{{/link-to}}

View File

@ -9,7 +9,7 @@
<div class="admin-container">
{{#if loading}}
<div class='admin-loading'>{{i18n loading}}</div>
{{loading-spinner}}
{{else}}
{{#if length}}
<table class='admin-flags'>
@ -32,12 +32,17 @@
{{#if flaggedPost.wasEdited}}<i class="fa fa-pencil" title="{{i18n admin.flags.was_edited}}"></i>{{/if}}
{{/if}}
{{/if}}
{{#if adminActiveFlagsView}}
{{#if flaggedPost.previous_flags_count}}
<span title="{{i18n admin.flags.previous_flags_count count=flaggedPost.previous_flags_count}}" class="badge-notification flagged-posts">{{flaggedPost.previous_flags_count}}</span>
{{/if}}
{{/if}}
</td>
<td class='excerpt'>
<h3>
{{#if flaggedPost.topic.isPrivateMessage}}
<span class="private-message-glyph">{{icon envelope}}</span>
<span class="private-message-glyph">{{fa-icon envelope}}</span>
{{/if}}
{{topic-status topic=flaggedPost.topic}}
<a href='{{unbound flaggedPost.url}}'>{{flaggedPost.topic.title}}</a>
@ -61,7 +66,7 @@
{{#link-to 'adminUser' user}}
{{user.username}}
{{/link-to}}
{{age flaggedAt}}
{{format-age flaggedAt}}
<br />
{{flagType}}
</td>
@ -83,7 +88,7 @@
{{/link-to}}
</td>
<td>
{{age disposedAt}}
{{format-age disposedAt}}
{{{dispositionIcon}}}
{{#if tookAction}}
<i class='fa fa-gavel' title='{{i18n admin.flags.took_action}}'></i>
@ -138,14 +143,14 @@
<tr>
<td colspan="4" class="action">
{{#if adminActiveFlagsView}}
<button title='{{i18n admin.flags.agree_title}}' class='btn' {{action showAgreeFlagModal flaggedPost}}><i class="fa fa-thumbs-o-up"></i>{{i18n admin.flags.agree}}&hellip;</button>
<button title='{{i18n admin.flags.agree_title}}' class='btn' {{action "showAgreeFlagModal" flaggedPost}}><i class="fa fa-thumbs-o-up"></i>{{i18n admin.flags.agree}}&hellip;</button>
{{#if flaggedPost.postHidden}}
<button title='{{i18n admin.flags.disagree_flag_unhide_post_title}}' class='btn' {{action disagreeFlags flaggedPost}}><i class="fa fa-thumbs-o-down"></i>{{i18n admin.flags.disagree_flag_unhide_post}}</button>
<button title='{{i18n admin.flags.disagree_flag_unhide_post_title}}' class='btn' {{action "disagreeFlags" flaggedPost}}><i class="fa fa-thumbs-o-down"></i>{{i18n admin.flags.disagree_flag_unhide_post}}</button>
{{else}}
<button title='{{i18n admin.flags.disagree_flag_title}}' class='btn' {{action disagreeFlags flaggedPost}}><i class="fa fa-thumbs-o-down"></i>{{i18n admin.flags.disagree_flag}}</button>
<button title='{{i18n admin.flags.disagree_flag_title}}' class='btn' {{action "disagreeFlags" flaggedPost}}><i class="fa fa-thumbs-o-down"></i>{{i18n admin.flags.disagree_flag}}</button>
{{/if}}
<button title='{{i18n admin.flags.defer_flag_title}}' class='btn' {{action deferFlags flaggedPost}}><i class="fa fa-external-link"></i>{{i18n admin.flags.defer_flag}}</button>
<button title='{{i18n admin.flags.delete_title}}' class='btn btn-danger' {{action showDeleteFlagModal flaggedPost}}><i class="fa fa-trash-o"></i>{{i18n admin.flags.delete}}&hellip;</button>
<button title='{{i18n admin.flags.defer_flag_title}}' class='btn' {{action "deferFlags" flaggedPost}}><i class="fa fa-external-link"></i>{{i18n admin.flags.defer_flag}}</button>
<button title='{{i18n admin.flags.delete_title}}' class='btn btn-danger' {{action "showDeleteFlagModal" flaggedPost}}><i class="fa fa-trash-o"></i>{{i18n admin.flags.delete}}&hellip;</button>
{{/if}}
</td>
</tr>
@ -155,7 +160,7 @@
</tbody>
</table>
{{#if view.loading}}
<div class='admin-loading'>{{i18n loading}}</div>
{{loading-spinner}}
{{/if}}
{{else}}

View File

@ -22,8 +22,8 @@
</div>
</div>
<div class='controls'>
<button {{action save}} {{bind-attr disabled="disableSave"}} class='btn'>{{i18n admin.customize.save}}</button>
<button {{action "save"}} {{bind-attr disabled="disableSave"}} class='btn'>{{i18n admin.customize.save}}</button>
{{#unless automatic}}
<a {{action destroy}} class='delete-link'>{{i18n admin.customize.delete}}</a>
<button {{action "destroy"}} class='btn btn-danger'><i class="fa fa-trash-o"></i>{{i18n admin.customize.delete}}</button>
{{/unless}}
</div>

View File

@ -4,13 +4,13 @@
<ul>
{{#each group in arrangedContent}}
<li>
<a href='#' {{action showGroup group}}>{{group.name}} <span class="count">{{group.userCountDisplay}}</span></a>
<a href='#' {{action "showGroup" group}}>{{group.name}} <span class="count">{{group.userCountDisplay}}</span></a>
</li>
{{/each}}
</ul>
<div class='controls'>
<button class='btn' {{bind-attr disabled="refreshingAutoGroups"}} {{action "refreshAutoGroups"}}><i class="fa fa-refresh"></i>{{i18n admin.groups.refresh}}</button>
<button class='btn' {{action newGroup}}><i class="fa fa-plus"></i>{{i18n admin.groups.new}}</button>
<button class='btn' {{action "newGroup"}}><i class="fa fa-plus"></i>{{i18n admin.groups.new}}</button>
</div>
</div>

View File

@ -2,5 +2,5 @@
<pre>{{details}}</pre>
</div>
<div class="modal-footer">
<button class='btn btn-primary' {{action closeModal}}>{{i18n close}}</button>
<button class='btn btn-primary' {{action "closeModal"}}>{{i18n close}}</button>
</div>

View File

@ -1,7 +1,7 @@
<p>{{i18n admin.logs.screened_emails.description}}</p>
{{#if loading}}
<div class='admin-loading'>{{i18n loading}}</div>
{{loading-spinner}}
{{else}}
{{#if model.length}}
@ -17,7 +17,7 @@
<div class="clearfix"></div>
</div>
{{view Discourse.ScreenedEmailsListView contentBinding="controller"}}
{{view 'screened-emails-list' content=controller}}
</div>
{{else}}

View File

@ -6,5 +6,5 @@
<div class="col last_match_at">{{age-with-tooltip last_match_at}}</div>
<div class="col created_at">{{age-with-tooltip created_at}}</div>
<div class="col ip_address">{{ip_address}}</div>
<div class="col action"><button class="btn" {{action clearBlock this}}><i class='fa fa-check'></i> {{i18n admin.logs.screened_emails.actions.allow}}</button></div>
<div class="col action"><button class="btn" {{action "clearBlock" this}}><i class='fa fa-check'></i> {{i18n admin.logs.screened_emails.actions.allow}}</button></div>
<div class="clearfix"></div>

View File

@ -4,7 +4,7 @@
<br/>
{{#if loading}}
<div class='admin-loading'>{{i18n loading}}</div>
{{loading-spinner}}
{{else}}
{{#if model.length}}
@ -19,7 +19,7 @@
<div class="clearfix"></div>
</div>
{{view Discourse.ScreenedIpAddressesListView contentBinding="controller"}}
{{view 'screened-ip-addresses-list' content=controller}}
</div>
{{else}}

View File

@ -0,0 +1,33 @@
<div class="col first ip_address">
{{#if editing}}
{{text-field value=ip_address autofocus="autofocus"}}
{{else}}
<span {{action "edit" this}}>{{ip_address}}</span>
{{/if}}
</div>
<div class="col action">
<i {{bind-attr class=":fa actionIcon"}}></i>
{{actionName}}
</div>
<div class="col match_count">{{match_count}}</div>
<div class="col last_match_at">
{{#if last_match_at}}
{{age-with-tooltip last_match_at}}
{{/if}}
</div>
<div class="col created_at">{{age-with-tooltip created_at}}</div>
<div class="col actions">
{{#unless editing}}
<button class="btn btn-danger" {{action "destroy" this}}><i class="fa fa-trash-o"></i></button>
<button class="btn" {{action "edit" this}}><i class="fa fa-pencil"></i></button>
{{#if isBlocked}}
<button class="btn" {{action "allow" this}}><i {{bind-attr class=":fa doNothingIcon"}}></i> {{i18n admin.logs.screened_ips.actions.do_nothing}}</button>
{{else}}
<button class="btn" {{action "block" this}}><i {{bind-attr class=":fa blockIcon"}}></i> {{i18n admin.logs.screened_ips.actions.block}}</button>
{{/if}}
{{else}}
<button class="btn" {{action "save" this}}>{{i18n admin.logs.save}}</button>
<a {{action "cancel" this}}>{{i18n cancel}}</a>
{{/unless}}
</div>
<div class="clearfix"></div>

View File

@ -1,33 +0,0 @@
<div class="col first ip_address">
{{#if editing}}
{{text-field value=ip_address autofocus="autofocus"}}
{{else}}
<span {{action edit this}}>{{ip_address}}</span>
{{/if}}
</div>
<div class="col action">
<i {{bind-attr class=":fa actionIcon"}}></i>
{{actionName}}
</div>
<div class="col match_count">{{match_count}}</div>
<div class="col last_match_at">
{{#if last_match_at}}
{{age-with-tooltip last_match_at}}
{{/if}}
</div>
<div class="col created_at">{{age-with-tooltip created_at}}</div>
<div class="col actions">
{{#unless editing}}
<button class="btn btn-danger" {{action destroy this}}><i class="fa fa-trash-o"></i></button>
<button class="btn" {{action edit this}}><i class="fa fa-pencil"></i></button>
{{#if isBlocked}}
<button class="btn" {{action allow this}}><i {{bind-attr class=":fa doNothingIcon"}}></i> {{i18n admin.logs.screened_ips.actions.do_nothing}}</button>
{{else}}
<button class="btn" {{action block this}}><i {{bind-attr class=":fa blockIcon"}}></i> {{i18n admin.logs.screened_ips.actions.block}}</button>
{{/if}}
{{else}}
<button class="btn" {{action save this}}>{{i18n admin.logs.save}}</button>
<a {{action cancel this}}>{{i18n cancel}}</a>
{{/unless}}
</div>
<div class="clearfix"></div>

View File

@ -1,7 +1,7 @@
<p>{{i18n admin.logs.screened_urls.description}}</p>
{{#if loading}}
<div class='admin-loading'>{{i18n loading}}</div>
{{loading-spinner}}
{{else}}
{{#if model.length}}
@ -15,7 +15,7 @@
<div class="clearfix"></div>
</div>
{{view Discourse.ScreenedUrlsListView contentBinding="controller"}}
{{view 'screened-urls-list' content=controller}}
</div>
{{else}}

View File

@ -1,10 +1,10 @@
<div>
<ul class="nav nav-pills">
<li {{bind-attr class="newSelected:active"}}>
<a href="#" {{action selectNew}}>{{i18n admin.logs.staff_actions.new_value}}</a>
<a href="#" {{action "selectNew"}}>{{i18n admin.logs.staff_actions.new_value}}</a>
</li>
<li {{bind-attr class="previousSelected:active"}}>
<a href="#" {{action selectPrevious}}>{{i18n admin.logs.staff_actions.previous_value}}</a>
<a href="#" {{action "selectPrevious"}}>{{i18n admin.logs.staff_actions.previous_value}}</a>
</li>
</ul>
<div class="modal-body">
@ -28,6 +28,6 @@
</div>
</div>
<div class="modal-footer">
<button class='btn btn-primary' {{action closeModal}}>{{i18n close}}</button>
<button class='btn btn-primary' {{action "closeModal"}}>{{i18n close}}</button>
</div>
</div>

View File

@ -1,27 +1,27 @@
<div class="staff-action-logs-controls">
<a {{action clearAllFilters}} {{bind-attr class=":clear-filters :filter filtersExists::invisible"}}>
<a {{action "clearAllFilters"}} {{bind-attr class=":clear-filters :filter filtersExists::invisible"}}>
<span class="label">{{i18n admin.logs.staff_actions.clear_filters}}</span>
</a>
{{#if actionFilter}}
<a {{action clearFilter "action_name"}} class="filter">
<a {{action "clearFilter" "action_name"}} class="filter">
<span class="label">{{i18n admin.logs.action}}</span>: {{actionFilter}}
<i class="fa fa-times-circle"></i>
</a>
{{/if}}
{{#if filters.acting_user}}
<a {{action clearFilter "acting_user"}} class="filter">
<a {{action "clearFilter" "acting_user"}} class="filter">
<span class="label">{{i18n admin.logs.staff_actions.staff_user}}</span>: {{filters.acting_user}}
<i class="fa fa-times-circle"></i>
</a>
{{/if}}
{{#if filters.target_user}}
<a {{action clearFilter "target_user"}} class="filter">
<a {{action "clearFilter" "target_user"}} class="filter">
<span class="label">{{i18n admin.logs.staff_actions.target_user}}</span>: {{filters.target_user}}
<i class="fa fa-times-circle"></i>
</a>
{{/if}}
{{#if filters.subject}}
<a {{action clearFilter "subject"}} class="filter">
<a {{action "clearFilter" "subject"}} class="filter">
<span class="label">{{i18n admin.logs.staff_actions.subject}}</span>: {{filters.subject}}
<i class="fa fa-times-circle"></i>
</a>
@ -45,10 +45,10 @@
{{#if loading}}
<br/>
<div class='admin-loading'>{{i18n loading}}</div>
{{loading-spinner}}
{{else}}
{{#if model.length}}
{{view Discourse.StaffActionLogsListView contentBinding="controller"}}
{{view "staff-action-logs-list" content=controller}}
{{else}}
{{i18n search.no_results}}
{{/if}}

View File

@ -1,27 +1,27 @@
<div class="col value first staff_user">
{{#link-to 'adminUser' acting_user}}{{avatar acting_user imageSize="tiny"}}{{/link-to}}
<a {{action filterByStaffUser acting_user}} class="btn btn-small">{{acting_user.username}}</a>
<a {{action "filterByStaffUser" acting_user}} class="btn btn-small">{{acting_user.username}}</a>
</div>
<div class="col value action">
<a {{action filterByAction action_name}} class="btn btn-small">{{actionName}}</a>
<a {{action "filterByAction" action_name}} class="btn btn-small">{{actionName}}</a>
</div>
<div class="col value subject">
{{#if target_user}}
{{#link-to 'adminUser' target_user}}{{avatar target_user imageSize="tiny"}}{{/link-to}}
<a {{action filterByTargetUser target_user}} class="btn btn-small">{{target_user.username}}</a>
<a {{action "filterByTargetUser" target_user}} class="btn btn-small">{{target_user.username}}</a>
{{/if}}
{{#if subject}}
<a {{action filterBySubject subject}} {{bind-attr title="subject"}} class="btn btn-small">{{subject}}</a>
<a {{action "filterBySubject" subject}} {{bind-attr title="subject"}} class="btn btn-small">{{subject}}</a>
{{/if}}
</div>
<div class="col value created_at">{{age-with-tooltip created_at}}</div>
<div class="col value details">
{{{formattedDetails}}}
{{#if useCustomModalForDetails}}
<a {{action showCustomDetailsModal this}}>{{i18n admin.logs.staff_actions.show}}</a>
<a {{action "showCustomDetailsModal" this}}>{{i18n admin.logs.staff_actions.show}}</a>
{{/if}}
{{#if useModalForDetails}}
<a {{action showDetailsModal this}}>{{i18n admin.logs.staff_actions.show}}</a>
<a {{action "showDetailsModal" this}}>{{i18n admin.logs.staff_actions.show}}</a>
{{/if}}
</div>
<div class="col value context">{{context}}</div>

View File

@ -0,0 +1,11 @@
{{#if user_deleted}}
<button title="{{i18n admin.flags.agree_flag_restore_post_title}}" {{action "agreeFlagRestorePost"}} class="btn"><i class="fa fa-thumbs-o-up"></i><i class="fa fa-eye"></i>{{i18n admin.flags.agree_flag_restore_post}}</button>
{{else}}
{{#unless postHidden}}
<button title="{{i18n admin.flags.agree_flag_hide_post_title}}" {{action "agreeFlagHidePost"}} class="btn"><i class="fa fa-thumbs-o-up"></i><i class="fa fa-eye-slash"></i>{{i18n admin.flags.agree_flag_hide_post}}</button>
{{/unless}}
{{/if}}
<button title="{{i18n admin.flags.agree_flag_title}}" {{action "agreeFlagKeepPost"}} class="btn"><i class="fa fa-thumbs-o-up"></i>{{i18n admin.flags.agree_flag}}</button>
{{#if canDeleteAsSpammer}}
<button title="{{i18n admin.flags.delete_spammer_title}}" {{action "deleteSpammer" user}} class="btn btn-danger"><i class="fa fa-exclamation-triangle"></i>{{i18n admin.flags.delete_spammer}}</button>
{{/if}}

View File

@ -1,7 +0,0 @@
{{#unless postHidden}}
<button title="{{i18n admin.flags.agree_flag_hide_post_title}}" {{action agreeFlagHidePost}} class="btn"><i class="fa fa-thumbs-o-up"></i><i class="fa fa-eye-slash"></i>{{i18n admin.flags.agree_flag_hide_post}}</button>
{{/unless}}
<button title="{{i18n admin.flags.agree_flag_title}}" {{action agreeFlagKeepPost}} class="btn"><i class="fa fa-thumbs-o-up"></i>{{i18n admin.flags.agree_flag}}</button>
{{#if canDeleteAsSpammer}}
<button title="{{i18n admin.flags.delete_spammer_title}}" {{action deleteSpammer user}} class="btn btn-danger"><i class="fa fa-exclamation-triangle"></i>{{i18n admin.flags.delete_spammer}}</button>
{{/if}}

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