diff --git a/app/controllers/cms/translate/access_logs_controller.rb b/app/controllers/cms/translate/access_logs_controller.rb
new file mode 100644
index 00000000000..85cb515633b
--- /dev/null
+++ b/app/controllers/cms/translate/access_logs_controller.rb
@@ -0,0 +1,34 @@
+class Cms::Translate::AccessLogsController < ApplicationController
+ include Cms::BaseFilter
+ include Cms::CrudFilter
+
+ model Translate::AccessLog
+ navi_view "cms/translate/main/navi"
+
+ public
+
+ def download
+ @item = Translate::DownloadParam.new
+ @item.save_term = '1.day'
+ return if request.get? || request.head?
+
+ @item.attributes = params.require(:item).permit(:encoding, :save_term)
+ if @item.invalid?
+ render
+ return
+ end
+
+ cond = { site_id: @cur_site.id }
+ items = @model.where(cond)
+ @item.save_term_in_time.try do |from|
+ items = items.gte(created: from)
+ end
+ items = items.reorder(created: 1)
+
+ enumerable = items.enum_csv(cur_site: @cur_site, encoding: @item.encoding)
+ filename = "translate_access_logs_#{Time.zone.now.to_i}.csv"
+
+ response.status = 200
+ send_enum enumerable, type: enumerable.content_type, filename: filename
+ end
+end
diff --git a/app/controllers/concerns/translate/public_filter.rb b/app/controllers/concerns/translate/public_filter.rb
index a6621b2c687..159d31fad64 100644
--- a/app/controllers/concerns/translate/public_filter.rb
+++ b/app/controllers/concerns/translate/public_filter.rb
@@ -11,8 +11,21 @@ def set_request_path_with_translate
return if !@cur_site.translate_enabled?
return if @cur_main_path !~ /^#{@cur_site.translate_location}\/.+?\//
+ deny_message = nil
if browser.bot?
- Rails.logger.info("translate denied due to a bot access: #{request.user_agent}")
+ deny_message = "bot access: #{request.user_agent}"
+ end
+ if @cur_site.translate_deny_no_refererr? && request.referer.blank?
+ deny_message = "no referer access"
+ end
+ Translate::AccessLog.create_log!(@cur_site, request) do |item|
+ item.path = request_path
+ item.remote_addr = remote_addr
+ item.deny_message = deny_message
+ end
+
+ if deny_message.present?
+ Rails.logger.info("translate denied due to a #{deny_message}")
return
end
diff --git a/app/jobs/translate/access_log/purge_job.rb b/app/jobs/translate/access_log/purge_job.rb
new file mode 100644
index 00000000000..9088dce0620
--- /dev/null
+++ b/app/jobs/translate/access_log/purge_job.rb
@@ -0,0 +1,21 @@
+class Translate::AccessLog::PurgeJob < Cms::ApplicationJob
+
+ DEFAULT_THRESHOLD_DAYS = 60
+
+ before_perform :set_items
+
+ def model
+ Translate::AccessLog
+ end
+
+ def perform
+ count = @items.destroy_all
+ Rails.logger.info "#{I18n.l(@threshold.to_date)}以前の#{model.model_name.human}を#{count}件削除しました。"
+ end
+
+ def set_items
+ @threshold = Time.zone.now - (site.translate_access_log_threshold || DEFAULT_THRESHOLD_DAYS).days
+ @items = model.site(site).lt(created: @threshold)
+ @items
+ end
+end
diff --git a/app/models/concerns/ss/addon/translate/site_setting.rb b/app/models/concerns/ss/addon/translate/site_setting.rb
index 62b87d299a3..4818a4dbf6a 100644
--- a/app/models/concerns/ss/addon/translate/site_setting.rb
+++ b/app/models/concerns/ss/addon/translate/site_setting.rb
@@ -33,6 +33,10 @@ module Translate::SiteSetting
field :translate_google_api_request_count, type: Integer, default: 0
field :translate_google_api_request_word_count, type: Integer, default: 0
+ # access log
+ field :translate_referer_restriction, type: String, default: "disabled"
+ field :translate_access_log_threshold, type: Integer, default: 60
+
permit_params :translate_state
permit_params :translate_source_id
permit_params translate_target_ids: []
@@ -53,6 +57,9 @@ module Translate::SiteSetting
permit_params :translate_google_api_request_count
permit_params :translate_google_api_request_word_count
+ permit_params :translate_referer_restriction
+ permit_params :translate_access_log_threshold
+
validates :translate_api, presence: true, if: -> { translate_enabled? }
validate :validate_translate_source, if: -> { translate_api.present? }
validate :validate_translate_targets, if: -> { translate_api.present? }
@@ -122,6 +129,17 @@ def translate_url
::File.join(url, translate_location, "/")
end
+ def translate_referer_restriction_options
+ [
+ [I18n.t("translate.options.referer_restriction.disabled"), "disabled"],
+ [I18n.t("translate.options.referer_restriction.enabled"), "enabled"],
+ ]
+ end
+
+ def translate_deny_no_refererr?
+ translate_referer_restriction == "enabled"
+ end
+
def find_translate_target(code)
translate_targets.select { |item| item.code == code }.first
end
diff --git a/app/models/translate/access_log.rb b/app/models/translate/access_log.rb
new file mode 100644
index 00000000000..b5fe352af9a
--- /dev/null
+++ b/app/models/translate/access_log.rb
@@ -0,0 +1,62 @@
+class Translate::AccessLog
+ include SS::Document
+ include SS::Reference::Site
+ include Cms::SitePermission
+
+ set_permission_name "cms_tools", :use
+
+ store_in_repl_master
+ index({ created: -1 })
+
+ field :path, type: String
+ field :remote_addr, type: String
+ field :user_agent, type: String
+ field :referer, type: String
+ field :deny_message, type: String
+
+ validates :path, presence: true
+
+ default_scope ->{ order_by(created: -1) }
+
+ def bot?
+ return false if user_agent.blank?
+ Browser.new(user_agent).bot?
+ end
+
+ class << self
+ def create_log!(site, request)
+ item = self.new
+ item.cur_site = site
+ item.path = request.path
+ item.user_agent = request.user_agent
+ item.remote_addr = request.remote_addr
+ item.referer = request.referer
+ yield item if block_given?
+ item.save!
+ item
+ end
+
+ def search(params = {})
+ criteria = self.where({})
+ return criteria if params.blank?
+
+ if params[:keyword].present?
+ criteria = criteria.keyword_in params[:keyword], :path
+ end
+ criteria
+ end
+
+ def enum_csv(options)
+ exporter = SS::Csv.draw(:export, context: self) do |drawer|
+ drawer.column :created
+ drawer.column :path
+ drawer.column :user_agent
+ drawer.column :remote_addr
+ drawer.column :referer
+ drawer.column :deny_message
+ end
+
+ exporter.enum(all, options)
+ end
+ end
+end
diff --git a/app/models/translate/download_param.rb b/app/models/translate/download_param.rb
new file mode 100644
index 00000000000..4c8e80f2fba
--- /dev/null
+++ b/app/models/translate/download_param.rb
@@ -0,0 +1,25 @@
+class Translate::DownloadParam
+ include ActiveModel::Model
+ include ActiveModel::Attributes
+
+ attr_accessor :cur_site, :cur_user
+
+ attribute :encoding, :string
+ attribute :save_term, :string
+
+ validates :encoding, presence: true, inclusion: { in: %w(Shift_JIS UTF-8), allow_blank: true }
+ validates :save_term, inclusion: { in: %w(1.day 1.month 1.year), allow_blank: true }
+
+ def save_term_options
+ %w(1.day 1.month 1.year).map do |v|
+ [ I18n.t("ss.options.duration.#{v.sub(".", "_")}"), v ]
+ end
+ end
+
+ def save_term_in_time(now = nil)
+ return if save_term.blank?
+
+ now ||= Time.zone.now
+ now - SS::Duration.parse(save_term)
+ end
+end
diff --git a/app/views/cms/translate/access_logs/_menu.html.erb b/app/views/cms/translate/access_logs/_menu.html.erb
new file mode 100644
index 00000000000..86685207bff
--- /dev/null
+++ b/app/views/cms/translate/access_logs/_menu.html.erb
@@ -0,0 +1,12 @@
+
diff --git a/app/views/cms/translate/access_logs/_show.html.erb b/app/views/cms/translate/access_logs/_show.html.erb
new file mode 100644
index 00000000000..dc5c9e03e16
--- /dev/null
+++ b/app/views/cms/translate/access_logs/_show.html.erb
@@ -0,0 +1,16 @@
+
+ - <%= @model.t :path %>
+ - <%= @item.path %>
+
+ - <%= @model.t :remote_addr %>
+ - <%= @item.remote_addr %>
+
+ - <%= @model.t :user_agent %>
+ - <%= @item.user_agent %>
+
+ - <%= @model.t :referer %>
+ - <%= @item.referer %>
+
+ - <%= @model.t :deny_message %>
+ - <%= @item.deny_message %>
+
diff --git a/app/views/cms/translate/access_logs/download.html.erb b/app/views/cms/translate/access_logs/download.html.erb
new file mode 100644
index 00000000000..f176f1a8c22
--- /dev/null
+++ b/app/views/cms/translate/access_logs/download.html.erb
@@ -0,0 +1,27 @@
+<%= form_for :item, url: { action: :download }, html: { method: :post } do |f| %>
+ <%= error_messages_for :item %>
+
+
+
+
+
+ - <%= t('ss.encoding') %>
+ -
+ <% %w(UTF-8 Shift_JIS).each do |encoding| %>
+
+ <% end %>
+
+
+ - <%= @item.class.human_attribute_name :save_term %>
+ - <%= f.select :save_term, @item.save_term_options, include_blank: t("history.options.duration.all_save") %>
+
+
+
+
+<% end %>
diff --git a/app/views/cms/translate/access_logs/index.html.erb b/app/views/cms/translate/access_logs/index.html.erb
new file mode 100644
index 00000000000..3e8b8e1e603
--- /dev/null
+++ b/app/views/cms/translate/access_logs/index.html.erb
@@ -0,0 +1,37 @@
+
+
+ <%= render template: "_search" %>
+
+
+
+ <% @items.each do |item| %>
+ -
+
+
+
+
+ <%= link_to item.path, { action: :show, id: item } %>
+
+
+
+ <%= ss_time_tag item.created %>
+ <%= @model.t :remote_addr %>
+ <%= item.remote_addr %>
+ <%= @model.t :user_agent %>
+ <%= item.user_agent %>
+ <%= @model.t :referer %>
+ <%= item.referer %>
+ <% if item.deny_message.present? %>
+ <%= @model.t :deny_message %>
+ <%= item.deny_message %>
+ <% end %>
+
+
+
+ <% end %>
+
+
+
+<%= paginate @items if @items.try(:current_page) %>
diff --git a/app/views/cms/translate/main/_navi.html.erb b/app/views/cms/translate/main/_navi.html.erb
index db583ab9ad8..5addbf9d7d2 100644
--- a/app/views/cms/translate/main/_navi.html.erb
+++ b/app/views/cms/translate/main/_navi.html.erb
@@ -3,6 +3,7 @@
<%= link_to t("translate.text_cache"), cms_translate_text_caches_path %>
<%= link_to t("translate.site_setting"), cms_translate_site_setting_path %>
<%= link_to t("translate.lang"), cms_translate_langs_path %>
+ <%= link_to t("translate.access_log"), cms_translate_access_logs_path %>
<%= render partial: "cms/main/conf_navi" %>
diff --git a/app/views/cms/translate/site_settings/_form_access_restriction.html.erb b/app/views/cms/translate/site_settings/_form_access_restriction.html.erb
new file mode 100644
index 00000000000..95d904895ff
--- /dev/null
+++ b/app/views/cms/translate/site_settings/_form_access_restriction.html.erb
@@ -0,0 +1,10 @@
+
+ - <%= @model.t :translate_referer_restriction %><%= @model.tt :translate_referer_restriction %>
+ - <%= f.select :translate_referer_restriction, @item.translate_referer_restriction_options %>
+
+ - <%= @model.t :translate_access_log_threshold %><%= @model.tt :translate_access_log_threshold %>
+ -
+ <%= f.number_field :translate_access_log_threshold, min: 0 %>
+ <%= t("datetime.prompts.day") %>
+
+
diff --git a/app/views/cms/translate/site_settings/_show_access_restriction.html.erb b/app/views/cms/translate/site_settings/_show_access_restriction.html.erb
new file mode 100644
index 00000000000..d2447db3c18
--- /dev/null
+++ b/app/views/cms/translate/site_settings/_show_access_restriction.html.erb
@@ -0,0 +1,7 @@
+
+ - <%= @model.t :translate_referer_restriction %>
+ - <%= @item.label :translate_referer_restriction %>
+
+ - <%= @model.t :translate_access_log_threshold %>
+ - <%= @item.translate_access_log_threshold %>
+
diff --git a/app/views/cms/translate/site_settings/edit.html.erb b/app/views/cms/translate/site_settings/edit.html.erb
index d7cb8bb2956..9f56df8a9b3 100644
--- a/app/views/cms/translate/site_settings/edit.html.erb
+++ b/app/views/cms/translate/site_settings/edit.html.erb
@@ -39,6 +39,18 @@
<% end %>
+
+ <%
+ addon_options = {}
+ addon_options[:id] = "addon-basic"
+ addon_options[:head] = I18n.t("translate.views.api_access_restriction")
+ %>
+ <% buf = render template: "_form_access_restriction", locals: { f: f, addon: addon_options } %>
+ <%= render "ss/crud/addon", addon: addon_options do %>
+ <%= buf %>
+ <% end %>
+
+