From 017efdece5c96b71bb43d07833259322bd0a76c8 Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Thu, 24 Oct 2013 17:18:10 -0400 Subject: [PATCH] A form to add ip addresses to be blocked or whitelisted --- .../screened_ip_address_form_component.js | 64 +++++++++++++++++++ ...n_logs_screened_ip_addresses_controller.js | 10 ++- .../admin/models/screened_ip_address.js | 18 +++--- .../logs/screened_ip_addresses.js.handlebars | 3 + .../screened-ip-address-form.handlebars | 4 ++ .../stylesheets/common/admin/admin_base.scss | 8 +++ .../admin/screened_ip_addresses_controller.rb | 9 +++ .../screened_ip_address_serializer.rb | 4 +- config/locales/client.en.yml | 6 +- config/routes.rb | 2 +- 10 files changed, 113 insertions(+), 15 deletions(-) create mode 100644 app/assets/javascripts/admin/components/screened_ip_address_form_component.js create mode 100644 app/assets/javascripts/discourse/templates/components/screened-ip-address-form.handlebars diff --git a/app/assets/javascripts/admin/components/screened_ip_address_form_component.js b/app/assets/javascripts/admin/components/screened_ip_address_form_component.js new file mode 100644 index 00000000000..dbae5a9aac9 --- /dev/null +++ b/app/assets/javascripts/admin/components/screened_ip_address_form_component.js @@ -0,0 +1,64 @@ +/** + A form to create an IP address that will be blocked or whitelisted. + Example usage: + + {{screened-ip-address-form action="recordAdded"}} + + where action is a callback on the controller or route that will get called after + the new record is successfully saved. It is called with the new ScreenedIpAddress record + as an argument. + + @class ScreenedIpAddressFormComponent + @extends Ember.Component + @namespace Discourse + @module Discourse +**/ +Discourse.ScreenedIpAddressFormComponent = Ember.Component.extend({ + classNames: ['screened-ip-address-form'], + formSubmitted: false, + actionName: 'block', + + 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')} + ]; + }.property(), + + actions: { + submit: function() { + if (!this.get('formSubmitted')) { + var self = this; + this.set('formSubmitted', true); + var screenedIpAddress = Discourse.ScreenedIpAddress.create({ip_address: this.get('ip_address'), action_name: this.get('actionName')}); + screenedIpAddress.save().then(function(result) { + self.set('ip_address', ''); + self.set('formSubmitted', false); + self.sendAction('action', Discourse.ScreenedIpAddress.create(result.screened_ip_address)); + Em.run.schedule('afterRender', function() { self.$('.ip-address-input').focus(); }); + }, function(e) { + self.set('formSubmitted', false); + var msg; + if (e.responseJSON && e.responseJSON.errors) { + msg = I18n.t("generic_error_with_reason", {error: e.responseJSON.errors.join('. ')}); + } else { + msg = I18n.t("generic_error"); + } + bootbox.alert(msg, function() { self.$('.ip-address-input').focus(); }); + }); + } + } + }, + + didInsertElement: function(e) { + var self = this; + this._super(); + Em.run.schedule('afterRender', function() { + self.$('.ip-address-input').keydown(function(e) { + if (e.keyCode === 13) { // enter key + self.send('submit'); + } + }); + }); + } +}); diff --git a/app/assets/javascripts/admin/controllers/admin_logs_screened_ip_addresses_controller.js b/app/assets/javascripts/admin/controllers/admin_logs_screened_ip_addresses_controller.js index 303b7fb3434..bbf06d69921 100644 --- a/app/assets/javascripts/admin/controllers/admin_logs_screened_ip_addresses_controller.js +++ b/app/assets/javascripts/admin/controllers/admin_logs_screened_ip_addresses_controller.js @@ -18,6 +18,12 @@ Discourse.AdminLogsScreenedIpAddressesController = Ember.ArrayController.extend( self.set('content', result); self.set('loading', false); }); + }, + + actions: { + recordAdded: function(arg) { + this.get("content").unshiftObject(arg); + } } }); @@ -27,12 +33,12 @@ Discourse.AdminLogsScreenedIpAddressController = Ember.ObjectController.extend({ actions: { allow: function(record) { - record.set('action', 'do_nothing'); + record.set('action_name', 'do_nothing'); this.send('save', record); }, block: function(record) { - record.set('action', 'block'); + record.set('action_name', 'block'); this.send('save', record); }, diff --git a/app/assets/javascripts/admin/models/screened_ip_address.js b/app/assets/javascripts/admin/models/screened_ip_address.js index 5a635214d1e..b209d7f6205 100644 --- a/app/assets/javascripts/admin/models/screened_ip_address.js +++ b/app/assets/javascripts/admin/models/screened_ip_address.js @@ -9,20 +9,20 @@ **/ Discourse.ScreenedIpAddress = Discourse.Model.extend({ actionName: function() { - return I18n.t("admin.logs.screened_ips.actions." + this.get('action')); - }.property('action'), + return I18n.t("admin.logs.screened_ips.actions." + this.get('action_name')); + }.property('action_name'), isBlocked: function() { - return (this.get('action') === 'block'); - }.property('action'), + return (this.get('action_name') === 'block'); + }.property('action_name'), actionIcon: function() { - if (this.get('action') === 'block') { + if (this.get('action_name') === 'block') { return this.get('blockIcon'); } else { return this.get('doNothingIcon'); } - }.property('action'), + }.property('action_name'), blockIcon: function() { return 'icon-ban-circle'; @@ -33,9 +33,9 @@ Discourse.ScreenedIpAddress = Discourse.Model.extend({ }.property(), save: function() { - return Discourse.ajax("/admin/logs/screened_ip_addresses/" + this.get('id') + ".json", { - type: 'PUT', - data: {ip_address: this.get('ip_address'), action_name: this.get('action')} + return Discourse.ajax("/admin/logs/screened_ip_addresses" + (this.id ? '/' + this.id : '') + ".json", { + type: this.id ? 'PUT' : 'POST', + data: {ip_address: this.get('ip_address'), action_name: this.get('action_name')} }); }, diff --git a/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.js.handlebars b/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.js.handlebars index b929daf340c..920306ae7e6 100644 --- a/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.js.handlebars +++ b/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.js.handlebars @@ -1,5 +1,8 @@

{{i18n admin.logs.screened_ips.description}}

+{{screened-ip-address-form action="recordAdded"}} +
+ {{#if loading}}
{{i18n loading}}
{{else}} diff --git a/app/assets/javascripts/discourse/templates/components/screened-ip-address-form.handlebars b/app/assets/javascripts/discourse/templates/components/screened-ip-address-form.handlebars new file mode 100644 index 00000000000..04ee5701372 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/components/screened-ip-address-form.handlebars @@ -0,0 +1,4 @@ +{{i18n admin.logs.screened_ips.form.label}} +{{textField value=ip_address disabled=formSubmitted class="ip-address-input" placeholderKey="admin.logs.screened_ips.form.ip_address" autocorrect="off" autocapitalize="off"}} +{{combobox content=actionNames value=actionName}} + diff --git a/app/assets/stylesheets/common/admin/admin_base.scss b/app/assets/stylesheets/common/admin/admin_base.scss index 01e1c933da9..19c86a13e14 100644 --- a/app/assets/stylesheets/common/admin/admin_base.scss +++ b/app/assets/stylesheets/common/admin/admin_base.scss @@ -752,6 +752,14 @@ table.api-keys { } } +.screened-ip-address-form { + margin-left: 6px; + .combobox { + width: 130px; + top: 10px; + } +} + .screened-emails, .screened-urls { .ip_address { width: 110px; diff --git a/app/controllers/admin/screened_ip_addresses_controller.rb b/app/controllers/admin/screened_ip_addresses_controller.rb index 974cf4c727d..00b5acb27ff 100644 --- a/app/controllers/admin/screened_ip_addresses_controller.rb +++ b/app/controllers/admin/screened_ip_addresses_controller.rb @@ -7,6 +7,15 @@ class Admin::ScreenedIpAddressesController < Admin::AdminController render_serialized(screened_ip_addresses, ScreenedIpAddressSerializer) end + def create + screened_ip_address = ScreenedIpAddress.new(allowed_params) + if screened_ip_address.save + render_serialized(screened_ip_address, ScreenedIpAddressSerializer) + else + render_json_error(screened_ip_address) + end + end + def update if @screened_ip_address.update_attributes(allowed_params) render json: success_json diff --git a/app/serializers/screened_ip_address_serializer.rb b/app/serializers/screened_ip_address_serializer.rb index d9d9048f59f..2f206792589 100644 --- a/app/serializers/screened_ip_address_serializer.rb +++ b/app/serializers/screened_ip_address_serializer.rb @@ -1,12 +1,12 @@ class ScreenedIpAddressSerializer < ApplicationSerializer attributes :id, :ip_address, - :action, + :action_name, :match_count, :last_match_at, :created_at - def action + def action_name ScreenedIpAddress.actions.key(object.action_type).to_s end diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 8cb26e22965..944550edb29 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1268,11 +1268,15 @@ en: url: "URL" screened_ips: title: "Screened IPs" - description: "IP addresses that are being watched." + description: 'IP addresses that are being watched. Use "Allow" to whitelist IP addresses.' delete_confirm: "Are you sure you want to remove the rule for %{ip_address}?" actions: block: "Block" do_nothing: "Allow" + form: + label: "New:" + ip_address: "IP address" + add: "Add" impersonate: title: "Impersonate User" diff --git a/config/routes.rb b/config/routes.rb index 20dfb54c6a4..2513694d1ad 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -69,7 +69,7 @@ Discourse::Application.routes.draw do scope '/logs' do resources :staff_action_logs, only: [:index] resources :screened_emails, only: [:index] - resources :screened_ip_addresses, only: [:index, :update, :destroy] + resources :screened_ip_addresses, only: [:index, :create, :update, :destroy] resources :screened_urls, only: [:index] end