diff --git a/Gemfile b/Gemfile index 7ec92d026a7..403576c2e65 100644 --- a/Gemfile +++ b/Gemfile @@ -98,6 +98,9 @@ gem 'unf' gem 'faraday' gem 'elasticsearch' +# line +gem 'line-bot-api' + group :development, :test do gem 'dotenv-rails' gem 'capybara', require: false diff --git a/Gemfile.lock b/Gemfile.lock index b4a46a4586e..6f19bbe090f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -297,6 +297,7 @@ GEM kramdown (~> 2.0) levenshtein (0.2.2) libv8 (7.3.492.27.1) + line-bot-api (1.19.0) link_header (0.0.8) liquid (4.0.1) listen (3.1.5) @@ -692,6 +693,7 @@ DEPENDENCIES kramdown kramdown-parser-gfm levenshtein + line-bot-api liquid mail-iso-2022-jp marcel diff --git a/app/assets/javascripts/cms/lib/form.js.erb b/app/assets/javascripts/cms/lib/form.js.erb index d8aa675f079..9019102f208 100644 --- a/app/assets/javascripts/cms/lib/form.js.erb +++ b/app/assets/javascripts/cms/lib/form.js.erb @@ -29,6 +29,7 @@ this.Cms_Form = (function () { // handle Form_Alert Form_Alert.addValidation(Form_Alert.clonedName); Form_Alert.addValidation(Form_Alert.closeConfirmation); + Form_Alert.addValidation(Form_Alert.snsPostConfirmation); if(Cms_Form.options.check.syntax) { Form_Alert.addAsyncValidation(Form_Alert.asyncValidateSyntaxCheck); } diff --git a/app/assets/javascripts/cms/lib/form_alert.js.erb b/app/assets/javascripts/cms/lib/form_alert.js.erb index cf166a9d651..b055a9ab3ea 100644 --- a/app/assets/javascripts/cms/lib/form_alert.js.erb +++ b/app/assets/javascripts/cms/lib/form_alert.js.erb @@ -159,6 +159,21 @@ this.Form_Alert = (function () { } }; + Form_Alert.snsPostConfirmation = function (form, submit) { + var addonName, messages, f; + f = $(submit).data("sns-post-confirmation"); + + messages = []; + if (f) { + messages = f(); + } + + addonName = '<%= I18n.t("cms.sns_post") %>'; + $.each(messages, function() { + Form_Alert.add(addonName, null, this); + }); + } + Form_Alert.add = function (addon, ele, msg) { var base; (base = Form_Alert.alerts)[addon] || (base[addon] = []); diff --git a/app/assets/stylesheets/ss/_pc_mb.scss b/app/assets/stylesheets/ss/_pc_mb.scss index 8fcecedd2b1..852b0c5c14a 100644 --- a/app/assets/stylesheets/ss/_pc_mb.scss +++ b/app/assets/stylesheets/ss/_pc_mb.scss @@ -3492,3 +3492,17 @@ body.ss-ajax-in-iframe { cursor: help; } } + +.sns-post-confirm { + background: #f3f3f3; + padding: 2px; + border-radius: 4px; + h2 { + font-weight: bold; + margin-top: 5px; + margin-left: 10px; + } + ul li { + list-style: inherit; + } +} diff --git a/app/controllers/cms/apis/sns_poster_controller.rb b/app/controllers/cms/apis/sns_poster_controller.rb new file mode 100644 index 00000000000..d90dbf7a4ac --- /dev/null +++ b/app/controllers/cms/apis/sns_poster_controller.rb @@ -0,0 +1,15 @@ +class Cms::Apis::SnsPosterController < ApplicationController + include Cms::BaseFilter + include Cms::CrudFilter + + model ::Cms::Page + + public + + def line_reset + set_item + @item = @item.becomes_with_route + @item.reset_line_posted if @item.respond_to?(:reset_line_posted) + redirect_to @item.private_show_path, notice: t("ss.notice.reset_posted") + end +end diff --git a/app/controllers/cms/sns_post/logs_controller.rb b/app/controllers/cms/sns_post/logs_controller.rb new file mode 100644 index 00000000000..ff6dfe141f5 --- /dev/null +++ b/app/controllers/cms/sns_post/logs_controller.rb @@ -0,0 +1,14 @@ +class Cms::SnsPost::LogsController < ApplicationController + include Cms::BaseFilter + include Cms::CrudFilter + + model Cms::SnsPostLog::Base + + navi_view "cms/sns_post/main/navi" + + private + + def set_crumbs + @crumbs << [t("cms.sns_post"), cms_sns_post_logs_path] + end +end diff --git a/app/controllers/concerns/cms/base_filter.rb b/app/controllers/concerns/cms/base_filter.rb index ce697de4109..968d0b42f5c 100644 --- a/app/controllers/concerns/cms/base_filter.rb +++ b/app/controllers/concerns/cms/base_filter.rb @@ -8,6 +8,7 @@ module Cms::BaseFilter helper Cms::NodeHelper helper Cms::FormHelper helper Map::MapHelper + helper Cms::SnsHelper before_action :validate_cms before_action :set_cms_assets before_action :set_site diff --git a/app/helpers/cms/sns_helper.rb b/app/helpers/cms/sns_helper.rb new file mode 100644 index 00000000000..cb592f757c2 --- /dev/null +++ b/app/helpers/cms/sns_helper.rb @@ -0,0 +1,46 @@ +module Cms::SnsHelper + def show_line_post_confirm? + return false if !@item.class.include?(Cms::Addon::LinePoster) + + site = @item.site + item = (@item.respond_to?(:master) && @item.master) ? @item.master : @item + + return false if !site.line_token_enabled? + return false if @item.line_auto_post != "active" + return false if item.line_posted.present? + true + end + + def show_twitter_post_confirm? + return false if !@item.class.include?(Cms::Addon::TwitterPoster) + + item = (@item.respond_to?(:master) && @item.master) ? @item.master : @item + + return false if !@item.use_twitter_post? + return false if item.twitter_posted.present? + true + end + + def render_sns_post_confirm + messages = [] + if show_line_post_confirm? + messages << t("cms.confirm.line_post_enabled") + end + if show_twitter_post_confirm? + messages << t("cms.confirm.twitter_post_enabled") + end + + return "" if messages.blank? + + h = [] + h << "
" + h << "

#{t("cms.confirm.when_publish")}

" + h << "
" + + return h.join("\n") + end +end diff --git a/app/jobs/concerns/chorg/mongoid_support.rb b/app/jobs/concerns/chorg/mongoid_support.rb index 916b4bb8970..063c992532d 100644 --- a/app/jobs/concerns/chorg/mongoid_support.rb +++ b/app/jobs/concerns/chorg/mongoid_support.rb @@ -47,7 +47,8 @@ def with_entities(models, scope = {}) entity_user.try(:cur_site=, @cur_site) entity.try(:cur_user=, entity_user) - entity.try(:skip_sns_post=, true) + entity.try(:skip_twitter_post=, true) + entity.try(:skip_line_post=, true) def entity.post_to_line; end def entity.post_to_twitter; end diff --git a/app/models/article/node.rb b/app/models/article/node.rb index 5a45941b3ca..4e6fed504aa 100644 --- a/app/models/article/node.rb +++ b/app/models/article/node.rb @@ -10,7 +10,8 @@ class Page include Cms::Addon::NodeSetting include Cms::Addon::Meta include Cms::Addon::EditorSetting - include Cms::Addon::NodeAutoPostSetting + include Cms::Addon::NodeTwitterPostSetting + include Cms::Addon::NodeLinePostSetting include Event::Addon::PageList include Cms::Addon::Form::Node include Category::Addon::Setting diff --git a/app/models/article/page.rb b/app/models/article/page.rb index 640d5ac7653..960b9fe6969 100644 --- a/app/models/article/page.rb +++ b/app/models/article/page.rb @@ -5,7 +5,8 @@ class Article::Page include Workflow::Addon::Branch include Workflow::Addon::Approver include Cms::Addon::Meta - include Cms::Addon::SnsPoster + include Cms::Addon::TwitterPoster + include Cms::Addon::LinePoster include Gravatar::Addon::Gravatar include Cms::Addon::Thumb include Cms::Addon::RedirectLink diff --git a/app/models/cms/node.rb b/app/models/cms/node.rb index 6957e798334..ca3f3bfc066 100644 --- a/app/models/cms/node.rb +++ b/app/models/cms/node.rb @@ -4,7 +4,8 @@ class Cms::Node include Cms::Addon::NodeSetting include Cms::Addon::EditorSetting include Cms::Addon::GroupPermission - include Cms::Addon::NodeAutoPostSetting + include Cms::Addon::NodeTwitterPostSetting + include Cms::Addon::NodeLinePostSetting include Cms::Addon::ForMemberNode index({ site_id: 1, filename: 1 }, { unique: true }) @@ -20,7 +21,8 @@ class Node include Cms::Addon::NodeSetting include Cms::Addon::Meta include Cms::Addon::EditorSetting - include Cms::Addon::NodeAutoPostSetting + include Cms::Addon::NodeTwitterPostSetting + include Cms::Addon::NodeLinePostSetting include Cms::Addon::NodeList include Cms::Addon::ChildList include Cms::Addon::ForMemberNode @@ -36,7 +38,8 @@ class Page include Cms::Addon::NodeSetting include Cms::Addon::Meta include Cms::Addon::EditorSetting - include Cms::Addon::NodeAutoPostSetting + include Cms::Addon::NodeTwitterPostSetting + include Cms::Addon::NodeLinePostSetting include Event::Addon::PageList include Cms::Addon::Form::Node include Cms::Addon::Release diff --git a/app/models/cms/page.rb b/app/models/cms/page.rb index d5f2ba694a2..16d61a87c5f 100644 --- a/app/models/cms/page.rb +++ b/app/models/cms/page.rb @@ -4,7 +4,8 @@ class Cms::Page include Workflow::Addon::Branch include Workflow::Addon::Approver include Cms::Addon::Meta - include Cms::Addon::SnsPoster + include Cms::Addon::TwitterPoster + include Cms::Addon::LinePoster include Gravatar::Addon::Gravatar include Cms::Addon::Thumb include Cms::Addon::Body diff --git a/app/models/cms/site.rb b/app/models/cms/site.rb index 4717fb9f928..9ca4f443760 100644 --- a/app/models/cms/site.rb +++ b/app/models/cms/site.rb @@ -9,7 +9,7 @@ class Cms::Site include SS::Addon::KanaSetting include SS::Addon::FacebookSetting include SS::Addon::TwitterSetting - include SS::Addon::SiteAutoPostSetting + include SS::Addon::LineSetting include SS::Addon::FileSetting include SS::Addon::MailSetting include SS::Addon::ApproveSetting diff --git a/app/models/cms/sns_post_log/base.rb b/app/models/cms/sns_post_log/base.rb new file mode 100644 index 00000000000..b005d636c80 --- /dev/null +++ b/app/models/cms/sns_post_log/base.rb @@ -0,0 +1,63 @@ +class Cms::SnsPostLog::Base + extend SS::Translation + include SS::Document + include SS::Reference::Site + include Cms::SitePermission + + store_in collection: 'cms_sns_post_logs' + + set_permission_name "cms_tools", :use + + field :name, type: String + field :action, type: String, default: "unknown" + field :state, type: String, default: "error" + field :error, type: String + + belongs_to :page, class_name: "Cms::Page" + + before_validation :set_name + validates :page_id, presence: true + + default_scope -> { order_by(created: -1) } + + index({ created: -1 }) + + def type + "base" + end + + def state_options + I18n.t("cms.options.sns_post_log_state").map { |k, v| [v, k] } + end + + def type_options + I18n.t("cms.options.sns_post_log_type").map { |k, v| [v, k] } + end + + def set_name + self.name = "[#{label(:state)}] #{label(:type)} #{created.strftime("%Y/%m/%d %H:%M")}" + end + + class << self + def create_with(page) + log = self.new + log.site = page.site + log.page = page + yield(log) + log.save + end + + def search(params) + criteria = self.where({}) + return criteria if params.blank? + + if params[:name].present? + criteria = criteria.search_text params[:name] + end + if params[:keyword].present? + criteria = criteria.keyword_in params[:keyword], :name, :body + end + criteria + end + end +end diff --git a/app/models/cms/sns_post_log/line.rb b/app/models/cms/sns_post_log/line.rb new file mode 100644 index 00000000000..97c3e14167b --- /dev/null +++ b/app/models/cms/sns_post_log/line.rb @@ -0,0 +1,13 @@ +class Cms::SnsPostLog::Line < Cms::SnsPostLog::Base + extend SS::Translation + include SS::Document + include Cms::Reference::Site + + field :messages, type: Array, default: [] + field :response_code, type: String + field :response_body, type: String + + def type + "line" + end +end diff --git a/app/models/cms/sns_post_log/twitter.rb b/app/models/cms/sns_post_log/twitter.rb new file mode 100644 index 00000000000..87f6b29e2b6 --- /dev/null +++ b/app/models/cms/sns_post_log/twitter.rb @@ -0,0 +1,14 @@ +class Cms::SnsPostLog::Twitter < Cms::SnsPostLog::Base + extend SS::Translation + include SS::Document + include Cms::Reference::Site + + field :message, type: String + field :media_files, type: Array, default: [] + field :destroy_post_ids, type: Array, default: [] + field :response_tweet, type: String + + def type + "twitter" + end +end diff --git a/app/models/concerns/cms/addon/line_poster.rb b/app/models/concerns/cms/addon/line_poster.rb new file mode 100644 index 00000000000..3d241b9a762 --- /dev/null +++ b/app/models/concerns/cms/addon/line_poster.rb @@ -0,0 +1,176 @@ +module Cms::Addon + module LinePoster + extend ActiveSupport::Concern + extend SS::Addon + + included do + attr_accessor :skip_line_post + + field :line_auto_post, type: String + field :line_posted, type: Array, default: [], metadata: { branch: false } + field :line_post_error, type: String, metadata: { branch: false } + + field :line_text_message, type: String + field :line_post_format, type: String + + validates :line_text_message, presence: true, if: -> { line_auto_post == "active" } + validates :thumb_id, presence: true, if: -> { line_auto_post == "active" && line_post_format == "thumb_carousel" } + validate :validate_line_title, if: -> { line_auto_post == "active" && name.present? } + validate :validate_line_text_message, if: -> { line_text_message.present? } + + permit_params :line_auto_post, :line_text_message, :line_post_format + + after_save :post_to_line + end + + def line_auto_post_options + %w(expired active).map { |v| [I18n.t("ss.options.state.#{v}"), v] } + end + + def line_post_format_options + %w(thumb_carousel body_carousel message_only_carousel).map { |v| [I18n.t("cms.options.line_post_format.#{v}"), v] } + end + + def line_post_enabled? + token_enabled = (site || @cur_site).try(:line_token_enabled?) + + return false if !token_enabled + return false if skip_line_post.present? + return false if line_auto_post != "active" + return false if respond_to?(:branch?) && branch? + return false if line_posted.present? + true + end + + def line_client + self.site = site || @cur_site + Line::Bot::Client.new do |config| + config.channel_secret = site.line_channel_secret + config.channel_token = site.line_channel_access_token + end + end + + def first_img_url + body = nil + body = html if respond_to?(:html) + body = column_values.map(&:to_html).join("\n") if respond_to?(:form) && form + SS::Html.extract_img_src(body, site.full_root_url) + end + + def first_img_full_url + img_url = first_img_url + return if img_url.blank? + img_url = ::File.join(site.full_root_url, img_url) if img_url.start_with?('/') + img_url + end + + def reset_line_posted + return if line_posted.blank? + Cms::SnsPostLog::Line.create_with(self) do |log| + log.created = Time.zone.now + log.action = "reset_line_posted" + self.set(line_posted: []) + log.state = "success" + end + end + + private + + def validate_line_title + if name.size > 40 + errors.add :name, :too_long_with_line_title, count: 40 + end + end + + def validate_line_text_message + if line_text_message.index("\n") + errors.add :line_text_message, :invalid_new_line_included + end + if line_text_message.size > 45 + errors.add :line_text_message, :too_long, count: 45 + end + end + + def post_to_line + return unless public? + return unless public_node? + return if @posted_to_line + + execute_post_to_line if line_post_enabled? + + @posted_to_line = true + end + + def execute_post_to_line + Cms::SnsPostLog::Line.create_with(self) do |log| + begin + posted_at = Time.zone.now + log.created = posted_at + log.action = "broadcast" + + client = line_client + messages = [] + if line_post_format == "thumb_carousel" + if thumb + messages << line_message_carousel(thumb.full_url) + else + raise I18n.t("errors.messages.thumb_is_blank") + end + elsif line_post_format == "body_carousel" + img_url = first_img_full_url + if img_url + messages << line_message_carousel(img_url) + else + raise I18n.t("errors.messages.not_found_file_url_in_body") + end + elsif line_post_format == "message_only_carousel" + messages << line_message_carousel + end + raise "messages blank" if messages.blank? + log.messages = messages + + res = client.broadcast(messages) + log.response_code = res.code + log.response_body = res.body + raise "#{res.code} #{res.body}" if res.code != "200" + + self.add_to_set(line_posted: posted_at) + self.unset(:line_post_error) + log.state = "success" + rescue => e + Rails.logger.fatal("post_to_line failed: #{e.class} (#{e.message}):\n #{e.backtrace.join("\n ")}") + log.error = "post_to_line failed: #{e.class} (#{e.message}):\n #{e.backtrace.join("\n ")}" + self.set(line_post_error: "#{e.class} (#{e.message})") + end + end + end + + def line_message_carousel(thumb_url = nil) + column = { + "title": name, + "text": line_text_message.to_s, + "actions": [ + { + "type": "uri", + "label": I18n.t("cms.visit_article"), + "uri": full_url + } + ] + } + + if thumb_url.present? + column["thumbnailImageUrl"] = thumb_url + column["imageBackgroundColor"] = "#FFFFFF" + end + + { + "type": "template", + "altText": name, + "template": { + "type": "carousel", + "columns": [column] + } + } + end + end +end diff --git a/app/models/concerns/cms/addon/node_line_post_setting.rb b/app/models/concerns/cms/addon/node_line_post_setting.rb new file mode 100644 index 00000000000..7e9e9672a9b --- /dev/null +++ b/app/models/concerns/cms/addon/node_line_post_setting.rb @@ -0,0 +1,18 @@ +module Cms::Addon::NodeLinePostSetting + extend ActiveSupport::Concern + extend SS::Addon + + included do + field :node_line_auto_post, type: String + field :node_line_post_format, type: String + permit_params :node_line_auto_post, :node_line_post_format + end + + def node_line_auto_post_options + %w(expired active).map { |v| [I18n.t("ss.options.state.#{v}"), v] } + end + + def node_line_post_format_options + I18n.t("cms.options.line_post_format").map { |k, v| [v, k] } + end +end diff --git a/app/models/concerns/cms/addon/node_auto_post_setting.rb b/app/models/concerns/cms/addon/node_twitter_post_setting.rb similarity index 62% rename from app/models/concerns/cms/addon/node_auto_post_setting.rb rename to app/models/concerns/cms/addon/node_twitter_post_setting.rb index d9891575d0f..80f238148db 100644 --- a/app/models/concerns/cms/addon/node_auto_post_setting.rb +++ b/app/models/concerns/cms/addon/node_twitter_post_setting.rb @@ -1,15 +1,13 @@ -module Cms::Addon::NodeAutoPostSetting +module Cms::Addon::NodeTwitterPostSetting extend ActiveSupport::Concern extend SS::Addon included do field :node_twitter_auto_post, type: String field :node_sns_auto_delete, type: String - field :node_edit_auto_post, type: String validates :node_twitter_auto_post, inclusion: { in: %w(expired active), allow_blank: true } validates :node_sns_auto_delete, inclusion: { in: %w(expired active), allow_blank: true } - validates :node_edit_auto_post, inclusion: { in: %w(expired active), allow_blank: true } - permit_params :node_sns_auto_delete, :node_edit_auto_post, :node_twitter_auto_post + permit_params :node_sns_auto_delete, :node_twitter_auto_post end def node_twitter_auto_post_options @@ -20,10 +18,6 @@ def node_sns_auto_delete_options %w(expired active).map { |v| [I18n.t("ss.options.state.#{v}"), v] } end - def node_edit_auto_post_options - %w(expired active).map { |v| [I18n.t("ss.options.state.#{v}"), v] } - end - def node_twitter_auto_post_enabled? node_twitter_auto_post == 'active' end @@ -31,8 +25,4 @@ def node_twitter_auto_post_enabled? def node_sns_auto_delete_enabled? node_sns_auto_delete == 'active' end - - def node_edit_auto_post_enabled? - node_edit_auto_post == 'active' - end end diff --git a/app/models/concerns/cms/addon/sns_poster.rb b/app/models/concerns/cms/addon/sns_poster.rb deleted file mode 100644 index 371170d5568..00000000000 --- a/app/models/concerns/cms/addon/sns_poster.rb +++ /dev/null @@ -1,151 +0,0 @@ -module Cms::Addon - module SnsPoster - extend ActiveSupport::Concern - include Cms::Content - extend SS::Addon - - # media_ids is restricted up to 4 - # see: https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-update - TWITTER_MAX_MEDIA_COUNT = 4 - - included do - attr_accessor :skip_sns_post - - field :twitter_auto_post, type: String - field :twitter_user_id, type: String, metadata: { branch: false } - field :twitter_post_id, type: String, metadata: { branch: false } - field :sns_auto_delete, type: String - field :edit_auto_post, type: String - field :twitter_posted, type: Array, default: [], metadata: { branch: false } - field :twitter_post_error, type: String, metadata: { branch: false } - - permit_params :twitter_auto_post, - :sns_auto_delete, - :edit_auto_post, - :twitter_post_id, - :twitter_user_id - - after_save :post_sns - after_remove_file :delete_sns - end - - def twitter_auto_post_options - %w(expired active).map { |v| [I18n.t("ss.options.state.#{v}"), v] } - end - - def sns_auto_delete_options - %w(expired active).map { |v| [I18n.t("ss.options.state.#{v}"), v] } - end - - def edit_auto_post_options - %w(expired active).map { |v| [I18n.t("ss.options.state.#{v}"), v] } - end - - def use_twitter_post? - twitter_auto_post == "active" - end - - def sns_auto_delete_enabled? - sns_auto_delete == "active" - end - - def edit_auto_post_enabled? - edit_auto_post == "active" - end - - def twitter_url(post_id, user_id) - "https://twitter.com/#{user_id}/status/#{post_id}" if - use_twitter_post? && user_id.present? && post_id.present? - end - - def twitter_post_enabled? - return false if skip_sns_post.present? - return false unless use_twitter_post? - return false if respond_to?(:branch?) && branch? - return true if edit_auto_post_enabled? - return false if twitter_posted.present? - true - end - - def connect_twitter - Twitter::REST::Client.new do |config| - config.consumer_key = self.site.twitter_consumer_key - config.consumer_secret = self.site.twitter_consumer_secret - config.access_token = self.site.twitter_access_token - config.access_token_secret = self.site.twitter_access_token_secret - end - end - - private - - def post_sns - return unless public? - return unless public_node? - return if @posted_sns - - # tweet - post_to_twitter if twitter_post_enabled? - - @posted_sns = true - end - - def post_to_twitter - tweet = "#{name}|#{full_url}" - client = connect_twitter - media_files = [] - # 画像の添付を収集 - attached_files.each do |file| - next if !file.image? - media_files << ::File.new(file.path) - break if media_files.length >= TWITTER_MAX_MEDIA_COUNT - end - if media_files.present? - # 画像の添付があれば update_with_media を用いて投稿 - twitter_param = client.update_with_media(tweet, media_files) - else - # 画像の添付がなければ update を用いて投稿 - twitter_param = client.update(tweet) - end - # 戻り値から投稿IDを取得し、DBに保存 - twitter_id = twitter_param.id - # URLを表示するためにスクリーンネームを取得し、DBに保存 - user_screen_id = client.user.screen_name - self.set(twitter_post_id: twitter_id, twitter_user_id: user_screen_id) - self.add_to_set(twitter_posted: { twitter_post_id: twitter_id.to_s, twitter_user_id: user_screen_id }) - self.unset(:twitter_post_error) - rescue => e - Rails.logger.fatal("post_to_twitter failed: #{e.class} (#{e.message}):\n #{e.backtrace.join("\n ")}") - self.set(twitter_post_error: "#{e.class} (#{e.message})") - ensure - if media_files.present? - media_files.each do |file| - file.close rescue nil - end - end - end - - def delete_sns - return if @deleted_sns - - if sns_auto_delete_enabled? - delete_sns_from_twitter - end - - @deleted_sns = true - end - - def delete_sns_from_twitter - return if twitter_posted.blank? - - client = connect_twitter - twitter_posted.to_a.each do |posted| - post_id = posted[:twitter_post_id] - client.destroy_status(post_id) rescue nil - end - self.unset(:twitter_post_id, :twitter_user_id, :twitter_posted, :twitter_post_error) rescue nil - rescue => e - Rails.logger.fatal("delete_sns_from_twitter failed: #{e.class} (#{e.message}):\n #{e.backtrace.join("\n ")}") - self.set(twitter_post_error: "#{e.class} (#{e.message})") - end - end -end diff --git a/app/models/concerns/cms/addon/twitter_poster.rb b/app/models/concerns/cms/addon/twitter_poster.rb new file mode 100644 index 00000000000..d9f10067400 --- /dev/null +++ b/app/models/concerns/cms/addon/twitter_poster.rb @@ -0,0 +1,173 @@ +module Cms::Addon + module TwitterPoster + extend ActiveSupport::Concern + include Cms::Content + extend SS::Addon + + # media_ids is restricted up to 4 + # see: https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-update + TWITTER_MAX_MEDIA_COUNT = 4 + + included do + attr_accessor :skip_twitter_post + + field :twitter_auto_post, type: String + field :twitter_user_id, type: String, metadata: { branch: false } + field :twitter_post_id, type: String, metadata: { branch: false } + field :sns_auto_delete, type: String + field :twitter_posted, type: Array, default: [], metadata: { branch: false } + field :twitter_post_error, type: String, metadata: { branch: false } + + permit_params :twitter_auto_post, + :sns_auto_delete, + :twitter_post_id, + :twitter_user_id + + after_save :post_to_twitter + after_remove_file :delete_sns + end + + def twitter_auto_post_options + %w(expired active).map { |v| [I18n.t("ss.options.state.#{v}"), v] } + end + + def sns_auto_delete_options + %w(expired active).map { |v| [I18n.t("ss.options.state.#{v}"), v] } + end + + def use_twitter_post? + twitter_auto_post == "active" + end + + def sns_auto_delete_enabled? + sns_auto_delete == "active" + end + + def twitter_url(post_id, user_id) + "https://twitter.com/#{user_id}/status/#{post_id}" if + use_twitter_post? && user_id.present? && post_id.present? + end + + def twitter_post_enabled? + token_enabled = (site || @cur_site).try(:twitter_token_enabled?) + + return false if !token_enabled + return false if skip_twitter_post.present? + return false if !use_twitter_post? + return false if respond_to?(:branch?) && branch? + return false if twitter_posted.present? + true + end + + def connect_twitter + Twitter::REST::Client.new do |config| + config.consumer_key = self.site.twitter_consumer_key + config.consumer_secret = self.site.twitter_consumer_secret + config.access_token = self.site.twitter_access_token + config.access_token_secret = self.site.twitter_access_token_secret + end + end + + private + + def post_to_twitter + return unless public? + return unless public_node? + return if @posted_to_twitter + + execute_post_to_twitter if twitter_post_enabled? + + @posted_to_twitter = true + end + + def execute_post_to_twitter + Cms::SnsPostLog::Twitter.create_with(self) do |log| + begin + posted_at = Time.zone.now + log.created = posted_at + + message = "#{name}|#{full_url}" + client = connect_twitter + media_files = tweet_media_files + + if media_files.present? + # 画像の添付があれば update_with_media を用いて投稿 + log.action = "update_with_media" + log.message = message + log.media_files = media_files.map(&:path) + tweet = client.update_with_media(message, media_files) + else + # 画像の添付がなければ update を用いて投稿 + log.action = "update" + log.message = message + tweet = client.update(message) + end + twitter_id = tweet.id + user_screen_id = client.user.screen_name + log.response_tweet = tweet.to_h.to_json + + self.set(twitter_post_id: twitter_id, twitter_user_id: user_screen_id) + self.add_to_set( + twitter_posted: { + twitter_post_id: twitter_id.to_s, + twitter_user_id: user_screen_id, + posted_at: Time.zone.now + } + ) + self.unset(:twitter_post_error) + log.state = "success" + rescue => e + Rails.logger.fatal("post_to_twitter failed: #{e.class} (#{e.message}):\n #{e.backtrace.join("\n ")}") + log.error = "post_to_twitter failed: #{e.class} (#{e.message}):\n #{e.backtrace.join("\n ")}" + self.set(twitter_post_error: "#{e.class} (#{e.message})") + end + end + end + + def delete_sns + return if @deleted_sns + + if sns_auto_delete_enabled? + delete_sns_from_twitter + end + + @deleted_sns = true + end + + def delete_sns_from_twitter + return if twitter_posted.blank? + Cms::SnsPostLog::Twitter.create_with(self) do |log| + posted_at = Time.zone.now + log.created = posted_at + log.state = "error" + + begin + log.action = "destroy_status" + client = connect_twitter + + twitter_posted.to_a.each do |posted| + post_id = posted[:twitter_post_id] + log.destroy_post_ids << post_id + client.destroy_status(post_id) rescue nil + end + self.unset(:twitter_post_id, :twitter_user_id, :twitter_posted, :twitter_post_error) + log.state = "success" + rescue => e + Rails.logger.fatal("delete_sns_from_twitter failed: #{e.class} (#{e.message}):\n #{e.backtrace.join("\n ")}") + log.error_message = "post_to_twitter failed: #{e.class} (#{e.message}):\n #{e.backtrace.join("\n ")}" + self.set(twitter_post_error: "#{e.class} (#{e.message})") + end + end + end + + def tweet_media_files + media_files = [] + attached_files.each do |file| + next if !file.image? + media_files << ::File.new(file.path) + break if media_files.length >= TWITTER_MAX_MEDIA_COUNT + end + media_files + end + end +end diff --git a/app/models/concerns/ss/addon/line_setting.rb b/app/models/concerns/ss/addon/line_setting.rb new file mode 100644 index 00000000000..a010756e36a --- /dev/null +++ b/app/models/concerns/ss/addon/line_setting.rb @@ -0,0 +1,14 @@ +module SS::Addon::LineSetting + extend ActiveSupport::Concern + extend SS::Addon + + included do + field :line_channel_secret, type: String + field :line_channel_access_token, type: String + permit_params :line_channel_secret, :line_channel_access_token + end + + def line_token_enabled? + line_channel_secret.present? && line_channel_access_token.present? + end +end diff --git a/app/models/concerns/ss/addon/site_auto_post_setting.rb b/app/models/concerns/ss/addon/site_auto_post_setting.rb deleted file mode 100644 index 68a7a7ee95e..00000000000 --- a/app/models/concerns/ss/addon/site_auto_post_setting.rb +++ /dev/null @@ -1,44 +0,0 @@ -module SS::Addon::SiteAutoPostSetting - extend ActiveSupport::Concern - extend SS::Addon - - included do - field :site_twitter_auto_post, type: String - field :site_sns_auto_delete, type: String - field :site_edit_auto_post, type: String - validates :site_twitter_auto_post, inclusion: { in: %w(expired active), allow_blank: true } - validates :site_sns_auto_delete, inclusion: { in: %w(expired active), allow_blank: true } - validates :site_edit_auto_post, inclusion: { in: %w(expired active), allow_blank: true } - permit_params :site_sns_auto_delete, :site_edit_auto_post, :site_twitter_auto_post - end - - def site_twitter_auto_post_options - %w(expired active).map do |v| - [I18n.t("ss.options.state.#{v}"), v] - end - end - - def site_sns_auto_delete_options - %w(expired active).map do |v| - [I18n.t("ss.options.state.#{v}"), v] - end - end - - def site_edit_auto_post_options - %w(expired active).map do |v| - [I18n.t("ss.options.state.#{v}"), v] - end - end - - def site_twitter_auto_post_enabled? - site_twitter_auto_post == 'active' - end - - def site_sns_auto_delete_enabled? - site_sns_auto_delete == 'active' - end - - def site_edit_auto_post_enabled? - site_edit_auto_post == 'active' - end -end diff --git a/app/models/concerns/workflow/addon/branch.rb b/app/models/concerns/workflow/addon/branch.rb index 229b3419d9d..438e5c29c69 100644 --- a/app/models/concerns/workflow/addon/branch.rb +++ b/app/models/concerns/workflow/addon/branch.rb @@ -159,7 +159,10 @@ def merge_to_master master.cur_user = @cur_user master.cur_site = @cur_site master.in_branch = self - master.merge_branch + if !master.merge_branch + Rails.logger.error("merge_branch : master save failed #{master.errors.full_messages.join(",")}") + end + master.generate_file end diff --git a/app/models/event/node.rb b/app/models/event/node.rb index 258789e507b..afba20d75e8 100644 --- a/app/models/event/node.rb +++ b/app/models/event/node.rb @@ -9,7 +9,8 @@ class Page include Cms::Addon::NodeSetting include Cms::Addon::Meta include Cms::Addon::EditorSetting - include Cms::Addon::NodeAutoPostSetting + include Cms::Addon::NodeTwitterPostSetting + include Cms::Addon::NodeLinePostSetting include Category::Addon::Setting include Event::Addon::CalendarList include Event::Addon::IcalImport diff --git a/app/models/event/page.rb b/app/models/event/page.rb index d8276357836..f217dd914b8 100644 --- a/app/models/event/page.rb +++ b/app/models/event/page.rb @@ -5,7 +5,8 @@ class Event::Page include Workflow::Addon::Branch include Workflow::Addon::Approver include Cms::Addon::Meta - include Cms::Addon::SnsPoster + include Cms::Addon::TwitterPoster + include Cms::Addon::LinePoster include Gravatar::Addon::Gravatar include Cms::Addon::RedirectLink include Cms::Addon::Body diff --git a/app/models/faq/node.rb b/app/models/faq/node.rb index d3f6ec06ca7..209480b01fc 100644 --- a/app/models/faq/node.rb +++ b/app/models/faq/node.rb @@ -10,7 +10,8 @@ class Page include Cms::Addon::NodeSetting include Cms::Addon::Meta include Cms::Addon::EditorSetting - include Cms::Addon::NodeAutoPostSetting + include Cms::Addon::NodeTwitterPostSetting + include Cms::Addon::NodeLinePostSetting include Event::Addon::PageList include Category::Addon::Setting include Cms::Addon::TagSetting diff --git a/app/models/faq/page.rb b/app/models/faq/page.rb index 9ea31400f49..75b6f1e4189 100644 --- a/app/models/faq/page.rb +++ b/app/models/faq/page.rb @@ -6,7 +6,8 @@ class Faq::Page include Workflow::Addon::Approver include Cms::Addon::Meta include Cms::Addon::EditorSetting - include Cms::Addon::SnsPoster + include Cms::Addon::TwitterPoster + include Cms::Addon::LinePoster include Gravatar::Addon::Gravatar include Faq::Addon::Question include Cms::Addon::Body diff --git a/app/models/ss/site.rb b/app/models/ss/site.rb index bb2e968f23e..06a04a030f9 100644 --- a/app/models/ss/site.rb +++ b/app/models/ss/site.rb @@ -6,7 +6,7 @@ class SS::Site include SS::Addon::KanaSetting include SS::Addon::FacebookSetting include SS::Addon::TwitterSetting - include SS::Addon::SiteAutoPostSetting + include SS::Addon::LineSetting include SS::Addon::FileSetting include SS::Addon::MailSetting include SS::Addon::TrashSetting diff --git a/app/views/cms/agents/addons/line_poster/_form.html.erb b/app/views/cms/agents/addons/line_poster/_form.html.erb new file mode 100644 index 00000000000..de9c75366c5 --- /dev/null +++ b/app/views/cms/agents/addons/line_poster/_form.html.erb @@ -0,0 +1,22 @@ +<% + return "" unless @cur_site.line_token_enabled? + + addon ||= local_assigns.fetch(:addon, {}) + addon[:display_body] = "hide" + + line_auto_post = @item.line_auto_post.presence || @cur_node.try(:node_line_auto_post).presence || "expired" + line_post_format = @item.line_post_format.presence || @cur_node.try(:node_line_post_format).presence || "thumb_carousel" +%> + +
+ <% if @cur_site.line_token_enabled? %> +
<%= @model.t :line_auto_post %><%= @model.tt :line_auto_post %>
+
<%= f.select :line_auto_post, @item.line_auto_post_options, selected: line_auto_post %>
+ +
<%= @model.t :line_post_format %><%= @model.tt :line_post_format %>
+
<%= f.select :line_post_format, @item.line_post_format_options, selected: line_post_format %>
+ +
<%= @model.t :line_text_message %><%= @model.tt :line_text_message %>
+
<%= f.text_area :line_text_message, placeholder: (@item.t :line_text_message_placeholder) %>
+ <% end %> +
diff --git a/app/views/cms/agents/addons/line_poster/_show.html.erb b/app/views/cms/agents/addons/line_poster/_show.html.erb new file mode 100644 index 00000000000..c80dadf7913 --- /dev/null +++ b/app/views/cms/agents/addons/line_poster/_show.html.erb @@ -0,0 +1,38 @@ +<% return if !@cur_site.line_token_enabled? %> + +
+
<%= @model.t :line_auto_post %>
+
<%= @item.label :line_auto_post %>
+ + <% if @item.line_auto_post == "active" %> +
<%= @model.t :line_post_format %>
+
<%= @item.label :line_post_format %>
+ +
<%= @model.t :line_text_message %>
+
<%=br @item.line_text_message %>
+ +
<%= @model.t :line_posted %>
+
+ <%= tryb { @item.line_posted.first.strftime("%Y/%m/%d %H:%M") } %> + <% if @item.allowed?(:release, @cur_user, site: @cur_site) && @item.line_posted.present? %> + <%= jquery do %> + $(".reset-sns-post").on("click", function() { + if (!confirm("<%= I18n.t('ss.confirm.reset_posted') %>")) { + return false; + } + }); + <% end %> +
+ <%= link_to t("ss.links.reset_posted"), cms_apis_line_reset_path(id: @item), class: "btn reset-sns-post", method: :post %> +
+ <% end %> +
+ + <% if @item.line_post_error.present? %> +
<%= @model.t :line_post_error %>
+
+
<%= br @item.line_post_error %>
+
+ <% end %> + <% end %> +
diff --git a/app/views/cms/agents/addons/node_line_post_setting/_form.html.erb b/app/views/cms/agents/addons/node_line_post_setting/_form.html.erb new file mode 100644 index 00000000000..14bd41d9db3 --- /dev/null +++ b/app/views/cms/agents/addons/node_line_post_setting/_form.html.erb @@ -0,0 +1,14 @@ +<% + return "" unless @cur_site.line_token_enabled? + + addon ||= local_assigns.fetch(:addon, {}) + addon[:display_body] = "hide" +%> + +
+
<%= @model.t :node_line_auto_post %><%= @model.tt :node_line_auto_post %>
+
<%= f.select :node_line_auto_post, @item.node_line_auto_post_options, include_blank: true %>
+ +
<%= @model.t :node_line_post_format %><%= @model.tt :node_line_post_format %>
+
<%= f.select :node_line_post_format, @item.node_line_post_format_options, include_blank: true %>
+
diff --git a/app/views/cms/agents/addons/node_line_post_setting/_show.html.erb b/app/views/cms/agents/addons/node_line_post_setting/_show.html.erb new file mode 100644 index 00000000000..5d9d43393bc --- /dev/null +++ b/app/views/cms/agents/addons/node_line_post_setting/_show.html.erb @@ -0,0 +1,9 @@ +<% return "" unless @cur_site.line_token_enabled? %> + +
+
<%= @model.t :node_line_auto_post %>
+
<%= @item.label :node_line_auto_post %>
+ +
<%= @model.t :node_line_post_format %>
+
<%= @item.label :node_line_post_format %>
+
diff --git a/app/views/cms/agents/addons/node_auto_post_setting/_form.html.erb b/app/views/cms/agents/addons/node_twitter_post_setting/_form.html.erb similarity index 77% rename from app/views/cms/agents/addons/node_auto_post_setting/_form.html.erb rename to app/views/cms/agents/addons/node_twitter_post_setting/_form.html.erb index 527e5ee6244..c285de6f5f7 100644 --- a/app/views/cms/agents/addons/node_auto_post_setting/_form.html.erb +++ b/app/views/cms/agents/addons/node_twitter_post_setting/_form.html.erb @@ -13,7 +13,4 @@
<%= @model.t :node_sns_auto_delete %><%= @model.tt :node_sns_auto_delete %>
<%= f.select :node_sns_auto_delete, @item.node_sns_auto_delete_options, include_blank: true %>
- -
<%= @model.t :node_edit_auto_post %><%= @model.tt :node_edit_auto_post %>
-
<%= f.select :node_edit_auto_post, @item.node_edit_auto_post_options, include_blank: true %>
diff --git a/app/views/cms/agents/addons/node_auto_post_setting/_show.html.erb b/app/views/cms/agents/addons/node_twitter_post_setting/_show.html.erb similarity index 78% rename from app/views/cms/agents/addons/node_auto_post_setting/_show.html.erb rename to app/views/cms/agents/addons/node_twitter_post_setting/_show.html.erb index 0ec68998887..205838a89fa 100644 --- a/app/views/cms/agents/addons/node_auto_post_setting/_show.html.erb +++ b/app/views/cms/agents/addons/node_twitter_post_setting/_show.html.erb @@ -8,7 +8,4 @@
<%= @model.t :node_sns_auto_delete %>
<%= @item.label :node_sns_auto_delete %>
- -
<%= @model.t :node_edit_auto_post %>
-
<%= @item.label :node_edit_auto_post %>
diff --git a/app/views/cms/agents/addons/sns_poster/_show.html.erb b/app/views/cms/agents/addons/sns_poster/_show.html.erb deleted file mode 100644 index 1c0fddcc74f..00000000000 --- a/app/views/cms/agents/addons/sns_poster/_show.html.erb +++ /dev/null @@ -1,23 +0,0 @@ -<% return "" unless @cur_site.twitter_token_enabled? %> - -
- <% if @cur_site.twitter_token_enabled? %> -
<%= @model.t :twitter_auto_post %>
-
<%= @item.label :twitter_auto_post %>
- <% @item.twitter_posted.to_a.each do |posted| %> -
<%= @item.twitter_url(posted[:twitter_post_id], posted[:twitter_user_id]) %>
- <% end %> - <% if @item.twitter_post_error.present? %> -
<%= @model.t :twitter_post_error %>
-
-
<%= br @item.twitter_post_error %>
-
- <% end %> - <% end %> - -
<%= @model.t :sns_auto_delete %>
-
<%= @item.label :sns_auto_delete %>
- -
<%= @model.t :edit_auto_post %>
-
<%= @item.label :edit_auto_post %>
-
diff --git a/app/views/cms/agents/addons/sns_poster/_form.html.erb b/app/views/cms/agents/addons/twitter_poster/_form.html.erb similarity index 59% rename from app/views/cms/agents/addons/sns_poster/_form.html.erb rename to app/views/cms/agents/addons/twitter_poster/_form.html.erb index 5201faddc17..15e85b62364 100644 --- a/app/views/cms/agents/addons/sns_poster/_form.html.erb +++ b/app/views/cms/agents/addons/twitter_poster/_form.html.erb @@ -4,9 +4,8 @@ addon ||= local_assigns.fetch(:addon, {}) addon[:display_body] = "hide" - twitter_auto_post = @item.twitter_auto_post.presence || @cur_node.try(:node_twitter_auto_post).presence || @cur_site.try(:site_twitter_auto_post).presence - sns_auto_delete = @item.sns_auto_delete.presence || @cur_node.try(:node_sns_auto_delete).presence || @cur_site.try(:site_sns_auto_delete).presence - edit_auto_post = @item.edit_auto_post.presence || @cur_node.try(:node_edit_auto_post).presence || @cur_site.try(:site_edit_auto_post).presence + twitter_auto_post = @item.twitter_auto_post.presence || @cur_node.try(:node_twitter_auto_post).presence || "expired" + sns_auto_delete = @item.sns_auto_delete.presence || @cur_node.try(:node_sns_auto_delete).presence || "expired" %>
@@ -17,7 +16,4 @@
<%= @model.t :sns_auto_delete %><%= @model.tt :sns_auto_delete %>
<%= f.select :sns_auto_delete, @item.sns_auto_delete_options, :selected => sns_auto_delete %>
- -
<%= @model.t :edit_auto_post %><%= @model.tt :edit_auto_post %>
-
<%= f.select :edit_auto_post, @item.edit_auto_post_options, :selected => edit_auto_post %>
diff --git a/app/views/cms/agents/addons/twitter_poster/_show.html.erb b/app/views/cms/agents/addons/twitter_poster/_show.html.erb new file mode 100644 index 00000000000..880a0ba1be8 --- /dev/null +++ b/app/views/cms/agents/addons/twitter_poster/_show.html.erb @@ -0,0 +1,28 @@ +<% return "" unless @cur_site.twitter_token_enabled? %> + +
+
<%= @model.t :twitter_auto_post %>
+
<%= @item.label :twitter_auto_post %>
+ + <% @item.twitter_posted.to_a.each do |posted| %> +
<%= @item.t :twitter_url %>
+
+ + <%= @item.twitter_url(posted[:twitter_post_id], posted[:twitter_user_id]) %> + +
+ +
<%= @item.t :twitter_posted_at %>
+
<%= tryb { posted[:posted_at].strftime("%Y/%m/%d %H:%M") } %>
+ <% end %> + + <% if @item.twitter_post_error.present? %> +
<%= @model.t :twitter_post_error %>
+
+
<%= br @item.twitter_post_error %>
+
+ <% end %> + +
<%= @model.t :sns_auto_delete %>
+
<%= @item.label :sns_auto_delete %>
+
diff --git a/app/views/cms/main/_conf_navi.html.erb b/app/views/cms/main/_conf_navi.html.erb index f6a62914d7f..1011cebdeb3 100644 --- a/app/views/cms/main/_conf_navi.html.erb +++ b/app/views/cms/main/_conf_navi.html.erb @@ -56,6 +56,9 @@ <% if SS.config.voice.disable.blank? && Voice::File.allowed?(:read, @cur_user, site: @cur_site) %>

<%= link_to t("voice.file"), voice_files_path %>

<% end %> + <% if true %> +

<%= link_to t("cms.sns_post"), cms_sns_post_logs_path %>

+ <% end %> <% if SS.config.recommend.disable.blank? && Recommend::History::Log.allowed?(:read, @cur_user, site: @cur_site) %>

<%= link_to t("recommend.main"), recommend_history_logs_tokens_path %>

<% end %> diff --git a/app/views/cms/pages/index.html.erb b/app/views/cms/pages/index.html.erb index 01eb5e544e0..716538d1991 100644 --- a/app/views/cms/pages/index.html.erb +++ b/app/views/cms/pages/index.html.erb @@ -1,15 +1,15 @@ <% @tap_menu = proc do |item| %> - <% - if params.dig(:s, :target) == 'descendant' - show_path = item.private_show_path - edit_path = File.join(show_path, 'edit') - delete_path = File.join(show_path, 'delete') - else - show_path = url_for(action: :show, id: item.id) - edit_path = url_for(action: :edit, id: item.id) - delete_path = url_for(action: :delete, id: item.id) - end - %> + <% + if params.dig(:s, :target) == 'descendant' + show_path = item.private_show_path + edit_path = File.join(show_path, 'edit') + delete_path = File.join(show_path, 'delete') + else + show_path = url_for(action: :show, id: item.id) + edit_path = url_for(action: :edit, id: item.id) + delete_path = url_for(action: :delete, id: item.id) + end + %> <%= link_to t('ss.links.show'), show_path if item.allowed?(:read, @cur_user, site: @cur_site) %> <%= link_to t('ss.links.edit'), edit_path if item.allowed?(:edit, @cur_user, site: @cur_site) %> <%= link_to t('ss.links.delete'), delete_path if item.allowed?(:delete, @cur_user, site: @cur_site) %> diff --git a/app/views/cms/sns_post/logs/_menu.html.erb b/app/views/cms/sns_post/logs/_menu.html.erb new file mode 100644 index 00000000000..44b79328cba --- /dev/null +++ b/app/views/cms/sns_post/logs/_menu.html.erb @@ -0,0 +1,6 @@ + diff --git a/app/views/cms/sns_post/logs/_show.html.erb b/app/views/cms/sns_post/logs/_show.html.erb new file mode 100644 index 00000000000..d3524f48dfd --- /dev/null +++ b/app/views/cms/sns_post/logs/_show.html.erb @@ -0,0 +1,63 @@ +<% + def try_parse_json(json) + JSON.parse(json) rescue json + end +%> + +
+
<%= @model.t :name %>
+
<%= @item.name %>
+ +
<%= @model.t :created %>
+
<%= tryb{ @item.created.strftime('%Y/%m/%d %H:%M') } %>
+ +
<%= @model.t :type %>
+
<%= @item.type %>
+ +
<%= @model.t :state %>
+
<%= @item.label(:state) %>
+ + <% if @item.page %> + <% page = @item.page.becomes_with_route %> +
<%= @model.t :page_id %>
+ + <% if page.allowed?(:read, @cur_user, site: @cur_site) %> +
<%= link_to page.name, page.private_show_path %>
+ <% else %> +
<%= page.name %>
+ <% end %> + <% end %> + + <% if @item.error.present? %> +
<%= @model.t :error %>
+
<%= @item.error %>
+ <% end %> + +
<%= @model.t :action %>
+
<%= @item.action %>
+ + <% if @item.type == "line" %> +
<%= @model.t :messages %>
+
<%= @item.messages %>
+ +
<%= @model.t :response_code %>
+
<%= @item.response_code %>
+ +
<%= @model.t :response_body %>
+
<%= try_parse_json(@item.response_body) %>
+ <% end %> + + <% if @item.type == "twitter" %> +
<%= @model.t :message %>
+
<%= @item.message %>
+ +
<%= @model.t :media_files %>
+
<%= @item.media_files %>
+ +
<%= @model.t :response_tweet %>
+
<%= try_parse_json(@item.response_tweet) %>
+ +
<%= @model.t :destroy_post_ids %>
+
<%= @item.destroy_post_ids %>
+ <% end %> +
diff --git a/app/views/cms/sns_post/logs/index.html.erb b/app/views/cms/sns_post/logs/index.html.erb new file mode 100644 index 00000000000..3d1ede24f23 --- /dev/null +++ b/app/views/cms/sns_post/logs/index.html.erb @@ -0,0 +1,12 @@ +<% @tap_menu = proc do |item| %> + <%= link_to t('ss.links.show'), { action: :show, id: item } if item.allowed?(:read, @cur_user, site: @cur_site) %> + <%= link_to t('ss.links.delete'), action: :delete, id: item if item.allowed?(:delete, @cur_user, site: @cur_site) %> +<% end %> + +<% @index_meta = proc do |item| %> + #<%= item.id %> + <%= item.label(:state) %> + <%= item.created.strftime("%Y/%m/%d %H:%M") %> +<% end %> + +<%= render file: "cms/crud/index" %> diff --git a/app/views/cms/sns_post/main/_navi.html.erb b/app/views/cms/sns_post/main/_navi.html.erb new file mode 100644 index 00000000000..3f205a71317 --- /dev/null +++ b/app/views/cms/sns_post/main/_navi.html.erb @@ -0,0 +1,6 @@ + + +<%= render partial: "cms/main/conf_navi" %> diff --git a/app/views/ss/agents/addons/line_setting/_form.html.erb b/app/views/ss/agents/addons/line_setting/_form.html.erb new file mode 100644 index 00000000000..9ac531f15cf --- /dev/null +++ b/app/views/ss/agents/addons/line_setting/_form.html.erb @@ -0,0 +1,11 @@ +<% + addon ||= local_assigns.fetch(:addon, {}) + addon[:display_body] = "hide" +%> +
+
<%= @model.t :line_channel_secret %><%= @model.tt :line_channel_secret %>
+
<%= f.text_field :line_channel_secret %>
+ +
<%= @model.t :line_channel_access_token %><%= @model.tt :line_channel_access_token %>
+
<%= f.text_field :line_channel_access_token %>
+
diff --git a/app/views/ss/agents/addons/line_setting/_show.html.erb b/app/views/ss/agents/addons/line_setting/_show.html.erb new file mode 100644 index 00000000000..c4ece93378e --- /dev/null +++ b/app/views/ss/agents/addons/line_setting/_show.html.erb @@ -0,0 +1,7 @@ +
+
<%= @model.t :line_channel_secret %>
+
<%= @item.line_channel_secret %>
+ +
<%= @model.t :line_channel_access_token %>
+
<%= @item.line_channel_access_token %>
+
diff --git a/app/views/ss/agents/addons/site_auto_post_setting/_form.html.erb b/app/views/ss/agents/addons/site_auto_post_setting/_form.html.erb deleted file mode 100644 index 11e88d2230f..00000000000 --- a/app/views/ss/agents/addons/site_auto_post_setting/_form.html.erb +++ /dev/null @@ -1,14 +0,0 @@ -<% - addon ||= local_assigns.fetch(:addon, {}) - addon[:display_body] = "hide" -%> -
-
<%= @model.t :site_twitter_auto_post %><%= @model.tt :site_twitter_auto_post %>
-
<%= f.select :site_twitter_auto_post, @item.site_twitter_auto_post_options, include_blank: true %>
- -
<%= @model.t :site_sns_auto_delete %><%= @model.tt :site_sns_auto_delete %>
-
<%= f.select :site_sns_auto_delete, @item.site_sns_auto_delete_options, include_blank: true %>
- -
<%= @model.t :site_edit_auto_post %><%= @model.tt :site_edit_auto_post %>
-
<%= f.select :site_edit_auto_post, @item.site_edit_auto_post_options, include_blank: true %>
-
diff --git a/app/views/ss/agents/addons/site_auto_post_setting/_show.html.erb b/app/views/ss/agents/addons/site_auto_post_setting/_show.html.erb deleted file mode 100644 index 61ef2052dca..00000000000 --- a/app/views/ss/agents/addons/site_auto_post_setting/_show.html.erb +++ /dev/null @@ -1,10 +0,0 @@ -
-
<%= @model.t :site_twitter_auto_post %>
-
<%= @item.label :site_twitter_auto_post %>
- -
<%= @model.t :site_sns_auto_delete %>
-
<%= @item.label :site_sns_auto_delete %>
- -
<%= @model.t :site_edit_auto_post %>
-
<%= @item.label :site_edit_auto_post %>
-
diff --git a/app/views/workflow/agents/addons/approver/_form.html.erb b/app/views/workflow/agents/addons/approver/_form.html.erb index 4d06d960c72..cd09cdf6d90 100644 --- a/app/views/workflow/agents/addons/approver/_form.html.erb +++ b/app/views/workflow/agents/addons/approver/_form.html.erb @@ -18,4 +18,51 @@ %> <%= jquery do %> var workflowApprover = new SS_WorkflowApprover(<%== js_options.to_json %>); + + <% if @ss_mode == :cms %> + var linePostConfirm = function() { + var linePostEnabled, lineTokenEnabled, linePosted, lineAutoPost; + + linePostEnabled = <%== @item.class.include?(Cms::Addon::LinePoster) %>; + lineTokenEnabled = <%== @cur_site.line_token_enabled? %> + lineAutoPost = $('[name="item[line_auto_post]"]').length && ($('[name="item[line_auto_post]"]').val() == "active"); + + <% item = (@item.respond_to?(:master) && @item.master) ? @item.master : @item %> + linePosted = <%== item.respond_to?(:line_posted) && item.line_posted.present? %>; + + if (!linePostEnabled) { return false; } + if (!lineTokenEnabled) { return false; } + if (!lineAutoPost) { return false; } + if (linePosted) { return false; } + return true; + }; + + var twitterPostConfirm = function() { + var twitterPostEnabled, twitterAutoPost, twitterPosted, editAutoPost; + + twitterPostEnabled = <%== @item.class.include?(Cms::Addon::TwitterPoster) %>; + twitterAutoPost = $('[name="item[twitter_auto_post]"]').length && ($('[name="item[twitter_auto_post]"]').val() == "active"); + + <% item = (@item.respond_to?(:master) && @item.master) ? @item.master : @item %> + twitterPosted = <%== item.respond_to?(:twitter_posted) && item.twitter_posted.present? %>; + + if (!twitterPostEnabled) { return false; } + if (!twitterAutoPost) { return false; } + if (twitterPosted) { return false; } + return true; + }; + + $(".publish_save").data("sns-post-confirmation", function() { + var messages + + messages = []; + if (linePostConfirm()) { + messages.push("<%= t("cms.confirm.line_post_enabled") %>") + } + if (twitterPostConfirm()) { + messages.push("<%= t("cms.confirm.twitter_post_enabled") %>") + } + return messages; + }); + <% end %> <% end %> diff --git a/app/views/workflow/agents/addons/approver/_show.html.erb b/app/views/workflow/agents/addons/approver/_show.html.erb index bcfcb5498a4..d991cef5eb8 100644 --- a/app/views/workflow/agents/addons/approver/_show.html.erb +++ b/app/views/workflow/agents/addons/approver/_show.html.erb @@ -16,6 +16,9 @@ <% if workflow_approver %>
<%= render "ss/crud/addon", addon: { head: "#{t("workflow.buttons.approve")}/#{t("workflow.buttons.remand")}#{@model.tt :approve_remand}".html_safe } do %> + <% if @ss_mode == :cms %> + <%== render_sns_post_confirm rescue nil %> + <% end %> <%= text_area :remand, :comment, value: "" %> <% if @ss_mode == :gws && @item.workflow_approver_attachment_enabled_at?(workflow_approver[:level]) %>
diff --git a/config/locales/cms/ja.yml b/config/locales/cms/ja.yml index cc9ccf74603..894f42f92c9 100644 --- a/config/locales/cms/ja.yml +++ b/config/locales/cms/ja.yml @@ -70,6 +70,7 @@ ja: source_cleaner: ソースクリーニング source_cleaner_template: ソースクリーニング syntax_check: アクセシビリティチェック + sns_post: SNS投稿連携 theme_template: Theme切り替え user: ユーザー view_page: 公開画面 @@ -109,6 +110,7 @@ ja: column_youtube_auto_width: enabled: 画面幅に合わせる disabled: 画面幅に合わせない + visit_article: 記事を見る adobe_reader: remark: @@ -144,6 +146,9 @@ ja: contains_urls_exists: このページへのリンク、関連記事、添付ファイルが以下のページに含まれています。 contains_urls_not_found: このページへのリンク、関連記事、添付ファイルが含まれているページは見つかりませんでした。 check_accessibility_manually: "セマンティックなマークアップであるか確認してください。\nコントラスト比に問題がないか確認してください。" + when_publish: 公開時の注意 + line_post_enabled: LINE連携が有効になっています。連携しない場合は、設定を解除してください。 + twitter_post_enabled: Twitter投稿が有効になっています。連携しない場合は、設定を解除してください。 notices: import_with_entry_form_is_not_supported: 次のフォームでは本文ブロックは出力されません。 restoring_public_content_from_trash: 非公開で復元されます。復元後、内容を確認うえ、公開してください。 @@ -326,7 +331,16 @@ ja: left: 左 center: 中央 right: 右 - + line_post_format: + thumb_carousel: サムネイル画像とLINEメッセージ + body_carousel: 本文内の最初の画像とLINEメッセージ + message_only_carousel: LINEメッセージ + sns_post_log_type: + twitter: Twitter投稿 + line: LINE投稿 + sns_post_log_state: + success: 成功 + error: エラー sns_share: fb_like: Facebook いいね! fb_share: Facebook シェア @@ -531,8 +545,9 @@ ja: cms/import/body: 本文 cms/edit_lock: 排他制御 cms/sns_share: SNS共有 - cms/sns_poster: SNS自動投稿設定 - cms/node_auto_post_setting: SNS自動投稿設定 + cms/twitter_poster: Twitter連携 + cms/node_twitter_post_setting: Twitter連携設定 + cms/node_line_post_setting: LINE連携設定 cms/captcha: 認証 cms/body_layout_html: HTML cms/default_release_plan: 公開予約の既定値 @@ -560,6 +575,9 @@ ja: cms/column/text_like: 制約条件 cms/column/select_like: 選択 cms/redirect_link: リンクページ + cms/site_search/keyword: 注目ワード + cms/site_search/history: 履歴 + cms/line_poster: LINE連携 mongoid: models: @@ -784,17 +802,19 @@ ja: cms/addon/sns_share: sns_share_states: 表示 sns_share_orders: 並び順 - cms/addon/sns_poster: - sns_poster: SNS自動投稿設定 - twitter_auto_post: Twitter自動投稿 + cms/addon/twitter_poster: + twitter_auto_post: Twitter投稿 + twitter_url: TweetURL + twitter_posted_at: 投稿日時 sns_auto_delete: 非公開時に投稿を削除 - edit_auto_post: 編集時に自動投稿 twitter_post_error: 投稿エラー - cms/addon/node_auto_post_setting: + cms/addon/node_twitter_post_setting: node_auto_post_setting: SNS自動投稿設定 - node_twitter_auto_post: Twitter自動投稿 + node_twitter_auto_post: Twitter投稿 node_sns_auto_delete: 非公開時に投稿を削除 - node_edit_auto_post: 編集時に自動投稿 + cms/addon/node_line_post_setting: + node_line_auto_post: LINE投稿 + node_line_post_format: 投稿形式 cms/addon/import/page: in_file: ファイル cms/addon/import/group: @@ -1014,6 +1034,18 @@ ja: low_vision_report_filepath: 視覚化検証結果 low_vision_source_filepath: 視覚化検証元画像 low_vision_result_filepath: 視覚化検証画像 + cms/addon/line_poster: + line_auto_post: LINE投稿 + line_post_format: 投稿形式 + line_text_message: LINEメッセージ + line_text_message_placeholder: "○月○日、○○○イベントが行われます。詳しくは、市ホームページをご覧ください。\n※全角45文字以内\n※改行はしないでください" + line_posted: 投稿日時 + line_post_error: 投稿エラー + cms/sns_post_log/base: + name: タイトル + type: 投稿SNS + state: ステータス + page_id: 連携ページ activemodel: attributes: @@ -1135,6 +1167,8 @@ ja: - 設定している代替テキストが妥当かどうか確認してください。 thums_is_not_an_image: には画像ファイルを指定してください。 unsupported_encoding: 対応していない文字コードです。 + thumb_is_blank: サムネイル画像が登録されていません。 + not_found_file_url_in_body: 本文内の画像が見つかりませんでした。 template: no_errors: エラーは見つかりませんでした。 @@ -2111,6 +2145,38 @@ ja: - インポートするファイルを設定します。 - ファイルはUTF-8またはShift_JISでエンコードされている必要があります。 + cms/addon/node_line_post_setting: + node_line_auto_post: + - 有効に設定すると公開時にLINE投稿をおこないます。 + node_line_post_format: + - 投稿形式を選択します。 + - + - ・サムネイル画像とLINEメッセージ + - サムネイル画像とLINEメッセージおよび記事へのリンクをカルーセル形式で投稿します。 + - + - ・本文内の最初の画像とLINEメッセージ + - 本文内の最初の画像とLINEメッセージおよび記事へのリンクをカルーセル形式で投稿します。 + - + - ・LINEメッセージのみ + - LINEメッセージと記事へのリンクをカルーセル形式で投稿します。 + + cms/addon/line_poster: + line_auto_post: + - 有効に設定すると公開時にLINE投稿をおこないます。 + line_post_format: + - 投稿形式を選択します。 + - + - ・サムネイル画像とLINEメッセージ + - サムネイル画像とLINEメッセージおよび記事へのリンクをカルーセル形式で投稿します。 + - + - ・本文内の最初の画像とLINEメッセージ + - 本文内の最初の画像とLINEメッセージおよび記事へのリンクをカルーセル形式で投稿します。 + - + - ・LINEメッセージのみ + - LINEメッセージと記事へのリンクをカルーセル形式で投稿します。 + line_text_message: + - LINEに投稿するメッセージを入力します。 + all_content: page_id: ページID node_id: フォルダーID diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 32b9d063895..261dcfaec92 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -124,6 +124,7 @@ ja: invalid_filename: は半角英数、アンダースコア、ハイフンのみ使用可能です。 invalid_csv: CSV形式のファイルを選択してください。 malformed_csv: CSVの形式が正しくありません。正しい形式のCSVファイルを選択してください。 + invalid_new_line_included: "に改行を含めることはできません。" invalid_email_included: に不正なメールアドレスが含まれています。 too_large_mail_size: "メールの添付ファイルサイズが大きすぎます。合計: %{size}(制限値: %{limit})" smtp_delivery_error: "メールを送信できませんでした。STMPエラーメッセージ: %{message}" @@ -139,6 +140,7 @@ ja: too_long: は%{count}文字以内で入力してください。 too_large: は%{count}件以内で入力してください。 too_short: は%{count}文字以上で入力してください。 + too_long_with_line_title: は%{count}文字以内で入力してください。(LINE投稿有りの場合) wrong_length: は%{count}文字で入力してください。 other_than: "は%{count}以外の値にしてください。" email: は有効な電子メールアドレスを入力してください。 diff --git a/config/locales/sns_poster/ja.yml b/config/locales/sns_poster/ja.yml index a18aaddfb19..7fb594d55de 100644 --- a/config/locales/sns_poster/ja.yml +++ b/config/locales/sns_poster/ja.yml @@ -5,12 +5,8 @@ ja: - Twitterへの自動投稿の設定を行います。 sns_auto_delete: - 記事非公開時にSNSへ投稿した内容を削除します。 - edit_auto_post: - - 記事編集時の自動投稿の設定を行います。 cms/addon/node_auto_post_setting: node_twitter_auto_post: - Twitterへの自動投稿の設定を行います。 node_sns_auto_delete: - 記事非公開時にSNSへ投稿した内容を削除します。 - node_edit_auto_post: - - 記事編集時の自動投稿の設定を行います。 diff --git a/config/locales/ss/ja.yml b/config/locales/ss/ja.yml index 96f8329c123..ce13d37a860 100644 --- a/config/locales/ss/ja.yml +++ b/config/locales/ss/ja.yml @@ -103,6 +103,7 @@ ja: send_email: メールを作成する send_message: メッセージを作成する copy_email_address: メールアドレスをコピー + reset_posted: 未投稿に戻す buttons: save: 保存 new: 新規作成 @@ -173,6 +174,7 @@ ja: send: 送信してよろしいですか? publish: 公開してよろしいですか? depublish: 非公開にしてよろしいですか? + reset_posted: 未投稿状態に戻してもよろしいですか? notice: saved: 保存しました。 deleted: 削除しました。 @@ -205,6 +207,7 @@ ja: unset_seen_all: 未読にしました。 set_star_all: スターをつけました。 unset_star_all: スターをはずしました。 + reset_posted: 未投稿に戻しました。 info: soft_delete: データの実削除ではなく無効状態として保存されます。 @@ -419,7 +422,7 @@ ja: ss/kana_setting: かな設定 ss/facebook_setting: Facebook設定 ss/twitter_setting: Twitter設定 - ss/site_auto_post_setting: SNS自動投稿設定 + ss/line_setting: Line設定 ss/approve_setting: 承認設定 ss/editor_setting: エディタ設定 ss/mail_setting: メール設定 @@ -649,10 +652,9 @@ ja: twitter_consumer_secret: コンシューマーシークレット twitter_access_token: アクセストークン twitter_access_token_secret: トークンシークレット - ss/addon/site_auto_post_setting: - site_twitter_auto_post: Twitter自動投稿 - site_sns_auto_delete: 非公開時に投稿を削除 - site_edit_auto_post: 編集時に自動投稿 + ss/addon/line_setting: + line_channel_secret: チャンネルシークレット + line_channel_access_token: チャンネルアクセストークン ss/addon/file_setting: file_resizing: 添付ファイルリサイズ file_resizing_width: 幅 @@ -1053,13 +1055,13 @@ ja: twitter_access_token_secret: - アクセストークンシークレット(Access Token Secret)を設定します。 - Twitterへの自動投稿に必須です。 - ss/addon/site_auto_post_setting: - site_twitter_auto_post: - - Twitterへの自動投稿の設定を行います。 - site_sns_auto_delete: - - 記事非公開時にSNSへ投稿した内容を削除します。 - site_edit_auto_post: - - 記事編集時の自動投稿の設定を行います。 + ss/addon/line_setting: + line_channel_secret: + - Lineのチャンネルシークレットを設定します。 + - Lineとの連携に必須です。 + line_channel_access_token: + - Lineのチャンネルアクセストークンを設定します。 + - Lineとの連携に必須です。 ss/addon/file_setting: file_resizing: - ページの添付ファイル(アップロード)のリサイズにてデフォルトサイズを設定できます。 diff --git a/config/routes/cms/routes_end.rb b/config/routes/cms/routes_end.rb index 665de416421..b8feb213404 100644 --- a/config/routes/cms/routes_end.rb +++ b/config/routes/cms/routes_end.rb @@ -140,6 +140,10 @@ resource :site_setting end + namespace "sns_post" do + resources :logs, only: [:index, :show, :destroy], concerns: [:deletion] + end + get "check_links" => "check_links#index" post "check_links" => "check_links#run" get "generate_nodes" => "generate_nodes#index" @@ -268,6 +272,8 @@ namespace "translate" do get "langs" => "langs#index" end + + post "sns_poster/:id/line_reset" => "sns_poster#line_reset", as: :line_reset end end diff --git a/spec/features/cms/sns_post/line/approval_spec.rb b/spec/features/cms/sns_post/line/approval_spec.rb new file mode 100644 index 00000000000..b5400ea98e8 --- /dev/null +++ b/spec/features/cms/sns_post/line/approval_spec.rb @@ -0,0 +1,232 @@ +require 'spec_helper' + +describe "article_pages line post", type: :feature, dbscope: :example, js: true do + let(:site) { cms_site } + let(:node) { create :article_node_page } + let(:item) { create :article_page, cur_node: node, state: "closed" } + + let(:user) { cms_user } + let!(:user1) { create(:cms_test_user, group_ids: user.group_ids, cms_role_ids: user.cms_role_ids) } + + let(:show_path) { article_page_path site.id, node, item } + let(:edit_path) { edit_article_page_path site.id, node, item } + + let(:line_text_message) { unique_id } + + context "approve and publish" do + before do + site.line_channel_secret = unique_id + site.line_channel_access_token = unique_id + site.save! + end + + context "post none" do + it "#edit" do + capture_line_bot_client do |capture| + # edit + login_cms_user + visit edit_path + + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.expired"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.message_only_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + within "form#item-form" do + click_on I18n.t("ss.buttons.draft_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + expect(capture.broadcast.count).to eq 0 + expect(capture.broadcast.messages).to eq nil + expect(Cms::SnsPostLog::Line.count).to eq 0 + + # send request + within ".mod-workflow-request" do + select I18n.t("mongoid.attributes.workflow/model/route.my_group"), from: "workflow_route" + click_on I18n.t("workflow.buttons.select") + click_on I18n.t("workflow.search_approvers.index") + end + + wait_for_cbox do + expect(page).to have_content(user1.long_name) + click_on user1.long_name + end + within ".mod-workflow-request" do + click_on I18n.t("workflow.buttons.request") + end + expect(page).to have_css(".mod-workflow-view dd", text: I18n.t("workflow.state.request")) + + # approve + login_user user1 + visit show_path + within ".mod-workflow-approve" do + expect(page).to have_no_css(".sns-post-confirm", text: I18n.t("cms.confirm.line_post_enabled")) + click_on I18n.t("workflow.buttons.approve") + end + within "#addon-workflow-agents-addons-approver" do + expect(page).to have_css("dd", text: I18n.t("ss.options.state.approve")) + end + within "#addon-cms-agents-addons-release" do + expect(page).to have_css("dd", text: I18n.t("ss.options.state.public")) + end + + visit show_path + within "#addon-cms-agents-addons-line_poster" do + have_css("dd", text: line_text_message) + end + expect(capture.broadcast.count).to eq 0 + expect(capture.broadcast.messages).to eq nil + expect(Cms::SnsPostLog::Line.count).to eq 0 + end + end + end + + context "post message_only_carousel" do + it "#edit" do + capture_line_bot_client do |capture| + # edit + login_cms_user + visit edit_path + + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.message_only_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + within "form#item-form" do + click_on I18n.t("ss.buttons.draft_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + expect(capture.broadcast.count).to eq 0 + expect(capture.broadcast.messages).to eq nil + expect(Cms::SnsPostLog::Line.count).to eq 0 + + # send request + within ".mod-workflow-request" do + select I18n.t("mongoid.attributes.workflow/model/route.my_group"), from: "workflow_route" + click_on I18n.t("workflow.buttons.select") + click_on I18n.t("workflow.search_approvers.index") + end + + wait_for_cbox do + expect(page).to have_content(user1.long_name) + click_on user1.long_name + end + within ".mod-workflow-request" do + click_on I18n.t("workflow.buttons.request") + end + expect(page).to have_css(".mod-workflow-view dd", text: I18n.t("workflow.state.request")) + + # approve + login_user user1 + visit show_path + within ".mod-workflow-approve" do + expect(page).to have_css(".sns-post-confirm", text: I18n.t("cms.confirm.line_post_enabled")) + click_on I18n.t("workflow.buttons.approve") + end + within "#addon-workflow-agents-addons-approver" do + expect(page).to have_css("dd", text: I18n.t("ss.options.state.approve")) + end + within "#addon-cms-agents-addons-release" do + expect(page).to have_css("dd", text: I18n.t("ss.options.state.public")) + end + + visit show_path + within "#addon-cms-agents-addons-line_poster" do + have_css("dd", text: line_text_message) + end + expect(capture.broadcast.count).to eq 1 + expect(capture.broadcast.messages.dig(0, :template, :type)).to eq "carousel" + expect(capture.broadcast.messages.dig(0, :altText)).to eq item.name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :title)).to eq item.name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :text)).to eq line_text_message + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :actions, 0, :uri)).to eq item.full_url + expect(Cms::SnsPostLog::Line.count).to eq 1 + end + end + + # with branch page + it "#edit" do + capture_line_bot_client do |capture| + # create branch + login_cms_user + visit show_path + within "#addon-workflow-agents-addons-branch" do + click_on I18n.t("workflow.create_branch") + expect(page).to have_link item.name + click_on item.name + end + expect(page).to have_link I18n.t("ss.links.edit") + + # edit + click_on I18n.t("ss.links.edit") + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.message_only_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + within "form#item-form" do + click_on I18n.t("ss.buttons.draft_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + expect(capture.broadcast.count).to eq 0 + expect(capture.broadcast.messages).to eq nil + expect(Cms::SnsPostLog::Line.count).to eq 0 + + # send request + within ".mod-workflow-request" do + select I18n.t("mongoid.attributes.workflow/model/route.my_group"), from: "workflow_route" + click_on I18n.t("workflow.buttons.select") + click_on I18n.t("workflow.search_approvers.index") + end + + wait_for_cbox do + expect(page).to have_content(user1.long_name) + click_on user1.long_name + end + within ".mod-workflow-request" do + click_on I18n.t("workflow.buttons.request") + end + expect(page).to have_css(".mod-workflow-view dd", text: I18n.t("workflow.state.request")) + + # approve + login_user user1 + visit show_path + within "#addon-workflow-agents-addons-branch" do + expect(page).to have_link item.name + click_on item.name + end + + within ".mod-workflow-approve" do + expect(page).to have_css(".sns-post-confirm", text: I18n.t("cms.confirm.line_post_enabled")) + click_on I18n.t("workflow.buttons.approve") + end + within "#addon-workflow-agents-addons-approver" do + expect(page).to have_css("dd", text: I18n.t("ss.options.state.approve")) + end + within "#addon-cms-agents-addons-release" do + expect(page).to have_css("dd", text: I18n.t("ss.options.state.public")) + end + + visit show_path + within "#addon-cms-agents-addons-line_poster" do + have_css("dd", text: line_text_message) + end + expect(capture.broadcast.count).to eq 1 + expect(capture.broadcast.messages.dig(0, :template, :type)).to eq "carousel" + expect(capture.broadcast.messages.dig(0, :altText)).to eq item.name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :title)).to eq item.name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :text)).to eq line_text_message + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :actions, 0, :uri)).to eq item.full_url + expect(Cms::SnsPostLog::Line.count).to eq 1 + end + end + end + end +end diff --git a/spec/features/cms/sns_post/line/basic_spec.rb b/spec/features/cms/sns_post/line/basic_spec.rb new file mode 100644 index 00000000000..7f298512a2c --- /dev/null +++ b/spec/features/cms/sns_post/line/basic_spec.rb @@ -0,0 +1,345 @@ +require 'spec_helper' + +describe "article_pages line post", type: :feature, dbscope: :example, js: true do + let(:site) { cms_site } + let(:user) { cms_user } + let(:node) { create :article_node_page } + let(:item) { create :article_page, cur_node: node, state: "closed" } + + let(:new_path) { new_article_page_path site.id, node } + let(:edit_path) { edit_article_page_path site.id, node, item } + + let(:name) { "sample" } + let(:line_text_message) { unique_id } + + context "publish directly" do + before do + site.line_channel_secret = unique_id + site.line_channel_access_token = unique_id + site.save! + + login_cms_user + end + + context "post none" do + it "#new" do + capture_line_bot_client do |capture| + visit new_path + within "form#item-form" do + fill_in "item[name]", with: name + end + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.expired"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.message_only_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + expect(capture.broadcast.count).to eq 0 + expect(capture.broadcast.messages).to eq nil + expect(Cms::SnsPostLog::Line.count).to eq 0 + end + end + + it "#edit" do + capture_line_bot_client do |capture| + visit edit_path + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.expired"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.message_only_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + within "#addon-cms-agents-addons-line_poster" do + have_css("dd", text: line_text_message) + end + expect(capture.broadcast.count).to eq 0 + expect(capture.broadcast.messages).to eq nil + expect(Cms::SnsPostLog::Line.count).to eq 0 + end + end + end + + context "post message_only_carousel" do + it "#new" do + capture_line_bot_client do |capture| + visit new_path + within "form#item-form" do + fill_in "item[name]", with: name + end + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.message_only_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + wait_for_cbox do + have_css("#alertExplanation", text: I18n.t("cms.confirm.line_post_enabled")) + click_on I18n.t("ss.buttons.ignore_alert") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + within "#addon-cms-agents-addons-line_poster" do + have_css("dd", text: line_text_message) + end + + expect(capture.broadcast.count).to eq 1 + expect(capture.broadcast.messages.dig(0, :template, :type)).to eq "carousel" + expect(capture.broadcast.messages.dig(0, :altText)).to eq name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :title)).to eq name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :text)).to eq line_text_message + expect(Cms::SnsPostLog::Line.count).to eq 1 + end + end + + it "#edit" do + capture_line_bot_client do |capture| + visit edit_path + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.message_only_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + wait_for_cbox do + have_css("#alertExplanation", text: I18n.t("cms.confirm.line_post_enabled")) + click_on I18n.t("ss.buttons.ignore_alert") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + within "#addon-cms-agents-addons-line_poster" do + have_css("dd", text: line_text_message) + end + + expect(capture.broadcast.count).to eq 1 + expect(capture.broadcast.messages.dig(0, :template, :type)).to eq "carousel" + expect(capture.broadcast.messages.dig(0, :altText)).to eq item.name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :title)).to eq item.name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :text)).to eq line_text_message + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :actions, 0, :uri)).to eq item.full_url + expect(Cms::SnsPostLog::Line.count).to eq 1 + end + end + end + + context "post thumb_carousel" do + let!(:file) do + tmp_ss_file( + Cms::TempFile, contents: "#{Rails.root}/spec/fixtures/ss/logo.png", user: user, site: site, node: node + ) + end + + it "#new" do + capture_line_bot_client do |capture| + visit new_path + within "form#item-form" do + fill_in "item[name]", with: name + end + + within "#addon-cms-agents-addons-thumb" do + first(".btn-file-upload").click + end + wait_for_cbox do + expect(page).to have_css(".file-view", text: file.name) + first("a[data-id='#{file.id}']").click + end + + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.thumb_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + wait_for_cbox do + have_css("#alertExplanation", text: I18n.t("cms.confirm.line_post_enabled")) + click_on I18n.t("ss.buttons.ignore_alert") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + within "#addon-cms-agents-addons-line_poster" do + have_css("dd", text: line_text_message) + end + + expect(capture.broadcast.count).to eq 1 + expect(capture.broadcast.messages.dig(0, :template, :type)).to eq "carousel" + expect(capture.broadcast.messages.dig(0, :altText)).to eq name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :title)).to eq name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :text)).to eq line_text_message + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, "thumbnailImageUrl")).to eq file.full_url + expect(Cms::SnsPostLog::Line.count).to eq 1 + end + end + + it "#edit" do + capture_line_bot_client do |capture| + visit edit_path + within "#addon-cms-agents-addons-thumb" do + first(".btn-file-upload").click + end + wait_for_cbox do + expect(page).to have_css(".file-view", text: file.name) + first("a[data-id='#{file.id}']").click + end + + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.thumb_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + wait_for_cbox do + have_css("#alertExplanation", text: I18n.t("cms.confirm.line_post_enabled")) + click_on I18n.t("ss.buttons.ignore_alert") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + within "#addon-cms-agents-addons-line_poster" do + have_css("dd", text: line_text_message) + end + + expect(capture.broadcast.count).to eq 1 + expect(capture.broadcast.messages.dig(0, :template, :type)).to eq "carousel" + expect(capture.broadcast.messages.dig(0, :altText)).to eq item.name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :title)).to eq item.name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :text)).to eq line_text_message + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :actions, 0, :uri)).to eq item.full_url + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, "thumbnailImageUrl")).to eq file.full_url + expect(Cms::SnsPostLog::Line.count).to eq 1 + end + end + end + + context "post body_carousel" do + let(:attach_file_path) { "#{Rails.root}/spec/fixtures/ss/file/keyvisual.gif" } + + it "#new" do + capture_line_bot_client do |capture| + visit new_path + ensure_addon_opened("#addon-cms-agents-addons-file") + within "#addon-cms-agents-addons-file" do + wait_cbox_open do + click_on I18n.t("ss.buttons.upload") + end + end + wait_for_cbox do + attach_file "item[in_files][]", attach_file_path + wait_cbox_close do + click_button I18n.t("ss.buttons.attach") + end + end + within '#selected-files' do + click_on I18n.t("sns.image_paste") + end + + within "form#item-form" do + fill_in "item[name]", with: name + end + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.body_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + wait_for_cbox do + have_css("#alertExplanation", text: I18n.t("cms.confirm.line_post_enabled")) + click_on I18n.t("ss.buttons.ignore_alert") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + within "#addon-cms-agents-addons-line_poster" do + have_css("dd", text: line_text_message) + end + + expect(capture.broadcast.count).to eq 1 + expect(capture.broadcast.messages.dig(0, :template, :type)).to eq "carousel" + expect(capture.broadcast.messages.dig(0, :altText)).to eq name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :title)).to eq name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :text)).to eq line_text_message + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, "thumbnailImageUrl")).to include(::File.basename(attach_file_path)) + expect(Cms::SnsPostLog::Line.count).to eq 1 + end + end + + it "#edit" do + capture_line_bot_client do |capture| + visit edit_path + ensure_addon_opened("#addon-cms-agents-addons-file") + within "#addon-cms-agents-addons-file" do + wait_cbox_open do + click_on I18n.t("ss.buttons.upload") + end + end + wait_for_cbox do + attach_file "item[in_files][]", attach_file_path + wait_cbox_close do + click_button I18n.t("ss.buttons.attach") + end + end + within '#selected-files' do + click_on I18n.t("sns.image_paste") + end + + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.body_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + wait_for_cbox do + have_css("#alertExplanation", text: I18n.t("cms.confirm.line_post_enabled")) + click_on I18n.t("ss.buttons.ignore_alert") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + within "#addon-cms-agents-addons-line_poster" do + have_css("dd", text: line_text_message) + end + + expect(capture.broadcast.count).to eq 1 + expect(capture.broadcast.messages.dig(0, :template, :type)).to eq "carousel" + expect(capture.broadcast.messages.dig(0, :altText)).to eq item.name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :title)).to eq item.name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :text)).to eq line_text_message + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :actions, 0, :uri)).to eq item.full_url + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, "thumbnailImageUrl")).to include(::File.basename(attach_file_path)) + expect(Cms::SnsPostLog::Line.count).to eq 1 + end + end + end + end +end diff --git a/spec/features/cms/sns_post/line/merge_spec.rb b/spec/features/cms/sns_post/line/merge_spec.rb new file mode 100644 index 00000000000..5a5bdc07798 --- /dev/null +++ b/spec/features/cms/sns_post/line/merge_spec.rb @@ -0,0 +1,178 @@ +require 'spec_helper' + +describe "article_pages line post", type: :feature, dbscope: :example, js: true do + let(:site) { cms_site } + let(:user) { cms_user } + let(:node) { create :article_node_page } + let(:item) { create :article_page, cur_node: node, state: "closed" } + + let(:new_path) { new_article_page_path site.id, node } + let(:show_path) { article_page_path site.id, node, item } + + let(:name) { "sample" } + let(:line_text_message) { unique_id } + + context "merge and publish" do + before do + site.line_channel_secret = unique_id + site.line_channel_access_token = unique_id + site.save! + + login_cms_user + end + + context "post none" do + it "#edit" do + capture_line_bot_client do |capture| + visit show_path + within "#addon-workflow-agents-addons-branch" do + click_on I18n.t("workflow.create_branch") + expect(page).to have_link item.name + click_on item.name + end + + expect(page).to have_link I18n.t("ss.links.edit") + click_on I18n.t("ss.links.edit") + + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.expired"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.message_only_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + visit show_path + within "#addon-cms-agents-addons-line_poster" do + have_css("dd", text: line_text_message) + end + expect(capture.broadcast.count).to eq 0 + expect(capture.broadcast.messages).to eq nil + expect(Cms::SnsPostLog::Line.count).to eq 0 + end + end + end + + context "post message_only_carousel" do + it "#edit" do + capture_line_bot_client do |capture| + visit show_path + within "#addon-workflow-agents-addons-branch" do + click_on I18n.t("workflow.create_branch") + expect(page).to have_link item.name + click_on item.name + end + + expect(page).to have_link I18n.t("ss.links.edit") + click_on I18n.t("ss.links.edit") + + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.message_only_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + wait_for_cbox do + have_css("#alertExplanation", text: I18n.t("cms.confirm.line_post_enabled")) + click_on I18n.t("ss.buttons.ignore_alert") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + visit show_path + within "#addon-cms-agents-addons-line_poster" do + have_css("dd", text: line_text_message) + end + expect(capture.broadcast.count).to eq 1 + expect(capture.broadcast.messages.dig(0, :template, :type)).to eq "carousel" + expect(capture.broadcast.messages.dig(0, :altText)).to eq item.name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :title)).to eq item.name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :text)).to eq line_text_message + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :actions, 0, :uri)).to eq item.full_url + expect(Cms::SnsPostLog::Line.count).to eq 1 + end + end + + # master page already posted + it "#edit" do + capture_line_bot_client do |capture| + # first post + visit show_path + within "#addon-workflow-agents-addons-branch" do + click_on I18n.t("workflow.create_branch") + expect(page).to have_link item.name + click_on item.name + end + + expect(page).to have_link I18n.t("ss.links.edit") + click_on I18n.t("ss.links.edit") + + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.message_only_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + wait_for_cbox do + have_css("#alertExplanation", text: I18n.t("cms.confirm.line_post_enabled")) + click_on I18n.t("ss.buttons.ignore_alert") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + visit show_path + within "#addon-cms-agents-addons-line_poster" do + have_css("dd", text: line_text_message) + end + expect(capture.broadcast.count).to eq 1 + expect(capture.broadcast.messages.dig(0, :template, :type)).to eq "carousel" + expect(capture.broadcast.messages.dig(0, :altText)).to eq item.name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :title)).to eq item.name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :text)).to eq line_text_message + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :actions, 0, :uri)).to eq item.full_url + expect(Cms::SnsPostLog::Line.count).to eq 1 + + # second post + visit show_path + within "#addon-workflow-agents-addons-branch" do + click_on I18n.t("workflow.create_branch") + expect(page).to have_link item.name + click_on item.name + end + + expect(page).to have_link I18n.t("ss.links.edit") + click_on I18n.t("ss.links.edit") + + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.active")) + fill_in "item[line_text_message]", with: "modified" + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + visit show_path + within "#addon-cms-agents-addons-line_poster" do + have_css("dd", text: "modified") + end + expect(capture.broadcast.count).to eq 1 + expect(capture.broadcast.messages.dig(0, :template, :type)).to eq "carousel" + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :text)).to eq line_text_message + expect(Cms::SnsPostLog::Line.count).to eq 1 + end + end + end + end +end diff --git a/spec/features/cms/sns_post/line/release_page_spec.rb b/spec/features/cms/sns_post/line/release_page_spec.rb new file mode 100644 index 00000000000..dbe75007254 --- /dev/null +++ b/spec/features/cms/sns_post/line/release_page_spec.rb @@ -0,0 +1,224 @@ +require 'spec_helper' + +describe "article_pages line post", type: :feature, dbscope: :example, js: true do + let(:site) { cms_site } + let(:node) { create :article_node_page } + let(:item) { create :article_page, cur_node: node, state: "closed" } + + let(:user) { cms_user } + let!(:user1) { create(:cms_test_user, group_ids: user.group_ids, cms_role_ids: user.cms_role_ids) } + + let(:show_path) { article_page_path site.id, node, item } + let(:edit_path) { edit_article_page_path site.id, node, item } + + let(:line_text_message) { unique_id } + let(:release_date) { Time.zone.at(1.day.from_now.to_i) } + + context "publish at release_date" do + before do + site.line_channel_secret = unique_id + site.line_channel_access_token = unique_id + site.save! + + login_cms_user + end + + context "post none" do + it "#edit" do + capture_line_bot_client do |capture| + visit edit_path + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + select I18n.t("ss.options.state.expired"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.message_only_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + + ensure_addon_opened("#addon-cms-agents-addons-release_plan") + within "#addon-cms-agents-addons-release_plan" do + fill_in 'item[release_date]', with: release_date.strftime("%Y/%m/%d %H:%M") + end + + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + within "#addon-cms-agents-addons-release" do + expect(page).to have_css('dd', text: I18n.t('ss.state.ready')) + end + expect(capture.broadcast.count).to eq 0 + expect(capture.broadcast.messages).to eq nil + expect(Cms::SnsPostLog::Line.count).to eq 0 + + Timecop.travel(release_date) do + job = Cms::Page::ReleaseJob.bind(site_id: node.site_id, node_id: node.id) + expect { job.perform_now }.to output.to_stdout + + login_cms_user + visit show_path + + within "#addon-cms-agents-addons-release" do + expect(page).to have_css('dd', text: I18n.t('ss.options.state.public')) + end + expect(capture.broadcast.count).to eq 0 + expect(capture.broadcast.messages).to eq nil + expect(Cms::SnsPostLog::Line.count).to eq 0 + end + end + end + end + + context "post message_only_carousel" do + it "#edit" do + capture_line_bot_client do |capture| + visit edit_path + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + select I18n.t("ss.options.state.active"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.message_only_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + + ensure_addon_opened("#addon-cms-agents-addons-release_plan") + within "#addon-cms-agents-addons-release_plan" do + fill_in 'item[release_date]', with: release_date.strftime("%Y/%m/%d %H:%M") + end + + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + wait_for_cbox do + have_css("#alertExplanation", text: I18n.t("cms.confirm.line_post_enabled")) + click_on I18n.t("ss.buttons.ignore_alert") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + within "#addon-cms-agents-addons-release" do + expect(page).to have_css('dd', text: I18n.t('ss.state.ready')) + end + expect(capture.broadcast.count).to eq 0 + expect(capture.broadcast.messages).to eq nil + expect(Cms::SnsPostLog::Line.count).to eq 0 + + Timecop.travel(release_date) do + job = Cms::Page::ReleaseJob.bind(site_id: node.site_id, node_id: node.id) + expect { job.perform_now }.to output.to_stdout + + login_cms_user + visit show_path + + within "#addon-cms-agents-addons-release" do + expect(page).to have_css('dd', text: I18n.t('ss.options.state.public')) + end + expect(capture.broadcast.count).to eq 1 + expect(capture.broadcast.messages.dig(0, :template, :type)).to eq "carousel" + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :text)).to eq line_text_message + expect(Cms::SnsPostLog::Line.count).to eq 1 + end + end + end + + # master and approve + it "#edit" do + capture_line_bot_client do |capture| + # create branch + login_cms_user + visit show_path + within "#addon-workflow-agents-addons-branch" do + click_on I18n.t("workflow.create_branch") + expect(page).to have_link item.name + click_on item.name + end + expect(page).to have_link I18n.t("ss.links.edit") + + # edit + click_on I18n.t("ss.links.edit") + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + select I18n.t("ss.options.state.active"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.message_only_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + + ensure_addon_opened("#addon-cms-agents-addons-release_plan") + within "#addon-cms-agents-addons-release_plan" do + fill_in 'item[release_date]', with: release_date.strftime("%Y/%m/%d %H:%M") + end + first("#addon-cms-agents-addons-release_plan").click + + within "form#item-form" do + click_on I18n.t("ss.buttons.draft_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + expect(capture.broadcast.count).to eq 0 + expect(capture.broadcast.messages).to eq nil + expect(Cms::SnsPostLog::Line.count).to eq 0 + + # send request + within ".mod-workflow-request" do + select I18n.t("mongoid.attributes.workflow/model/route.my_group"), from: "workflow_route" + click_on I18n.t("workflow.buttons.select") + click_on I18n.t("workflow.search_approvers.index") + end + + wait_for_cbox do + expect(page).to have_content(user1.long_name) + click_on user1.long_name + end + within ".mod-workflow-request" do + click_on I18n.t("workflow.buttons.request") + end + expect(page).to have_css(".mod-workflow-view dd", text: I18n.t("workflow.state.request")) + + # approve + login_user user1 + visit show_path + within "#addon-workflow-agents-addons-branch" do + expect(page).to have_link item.name + click_on item.name + end + + within ".mod-workflow-approve" do + expect(page).to have_css(".sns-post-confirm", text: I18n.t("cms.confirm.line_post_enabled")) + click_on I18n.t("workflow.buttons.approve") + end + within "#addon-workflow-agents-addons-approver" do + expect(page).to have_css("dd", text: I18n.t("ss.options.state.approve")) + end + within "#addon-cms-agents-addons-release" do + expect(page).to have_css("dd", text: I18n.t("ss.options.state.ready")) + end + + visit show_path + within "#addon-cms-agents-addons-line_poster" do + have_css("dd", text: line_text_message) + end + expect(capture.broadcast.count).to eq 0 + expect(capture.broadcast.messages).to eq nil + expect(Cms::SnsPostLog::Line.count).to eq 0 + + Timecop.travel(release_date) do + job = Cms::Page::ReleaseJob.bind(site_id: node.site_id, node_id: node.id) + expect { job.perform_now }.to output.to_stdout + + login_cms_user + visit show_path + + within "#addon-cms-agents-addons-release" do + expect(page).to have_css('dd', text: I18n.t('ss.options.state.public')) + end + + expect(capture.broadcast.count).to eq 1 + expect(capture.broadcast.messages.dig(0, :template, :type)).to eq "carousel" + expect(capture.broadcast.messages.dig(0, :altText)).to eq item.name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :title)).to eq item.name + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :text)).to eq line_text_message + expect(capture.broadcast.messages.dig(0, :template, :columns, 0, :actions, 0, :uri)).to eq item.full_url + expect(Cms::SnsPostLog::Line.count).to eq 1 + end + end + end + end + end +end diff --git a/spec/features/cms/sns_post/logs/basic_spec.rb b/spec/features/cms/sns_post/logs/basic_spec.rb new file mode 100644 index 00000000000..9b8cfc2c53f --- /dev/null +++ b/spec/features/cms/sns_post/logs/basic_spec.rb @@ -0,0 +1,90 @@ +require 'spec_helper' + +describe "cms_pages sns post", type: :feature, dbscope: :example, js: true do + let(:site) { cms_site } + let(:user) { cms_user } + let(:node) { create :cms_node_page } + let(:item) { create :cms_page, cur_node: node, state: "closed" } + + let(:edit_path) { edit_cms_page_path site.id, node, item } + let(:index_path) { cms_sns_post_logs_path site.id } + + let(:line_text_message) { unique_id } + + context "publish directly" do + before do + site.line_channel_secret = unique_id + site.line_channel_access_token = unique_id + + site.twitter_username = unique_id + site.twitter_consumer_key = unique_id + site.twitter_consumer_secret = unique_id + site.twitter_access_token = unique_id + site.twitter_access_token_secret = unique_id + site.save! + + login_cms_user + end + + context "post message" do + it "#edit" do + capture_line_bot_client do |c1| + capture_twitter_rest_client do |c2| + visit edit_path + ensure_addon_opened("#addon-cms-agents-addons-line_poster") + within "#addon-cms-agents-addons-line_poster" do + select I18n.t("ss.options.state.active"), from: "item[line_auto_post]" + select I18n.t("cms.options.line_post_format.message_only_carousel"), from: "item[line_post_format]" + fill_in "item[line_text_message]", with: line_text_message + end + + ensure_addon_opened("#addon-cms-agents-addons-twitter_poster") + within "#addon-cms-agents-addons-twitter_poster" do + select I18n.t("ss.options.state.active"), from: "item[twitter_auto_post]" + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + wait_for_cbox do + have_css("#alertExplanation", text: I18n.t("cms.confirm.line_post_enabled")) + have_css("#alertExplanation", text: I18n.t("cms.confirm.twitter_post_enabled")) + click_on I18n.t("ss.buttons.ignore_alert") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + expect(Cms::SnsPostLog::Twitter.count).to eq 1 + expect(Cms::SnsPostLog::Line.count).to eq 1 + + visit index_path + within ".list-items" do + expect(page).to have_css("a", text: I18n.t("cms.options.sns_post_log_type.line")) + expect(page).to have_css("a", text: I18n.t("cms.options.sns_post_log_type.twitter")) + end + + # delete line log + within ".list-items" do + first("a", text: I18n.t("cms.options.sns_post_log_type.line")).click + end + expect(page).to have_link item.name + click_on I18n.t("ss.links.delete") + click_on I18n.t("ss.buttons.delete") + expect(page).to have_css('#notice', text: I18n.t('ss.notice.deleted')) + expect(Cms::SnsPostLog::Twitter.count).to eq 1 + expect(Cms::SnsPostLog::Line.count).to eq 0 + + # delete twitter log + within ".list-items" do + first("a", text: I18n.t("cms.options.sns_post_log_type.twitter")).click + end + expect(page).to have_link item.name + click_on I18n.t("ss.links.delete") + click_on I18n.t("ss.buttons.delete") + expect(page).to have_css('#notice', text: I18n.t('ss.notice.deleted')) + expect(Cms::SnsPostLog::Twitter.count).to eq 0 + expect(Cms::SnsPostLog::Line.count).to eq 0 + end + end + end + end + end +end diff --git a/spec/features/cms/sns_post/twitter/approval_spec.rb b/spec/features/cms/sns_post/twitter/approval_spec.rb new file mode 100644 index 00000000000..eb662a4729f --- /dev/null +++ b/spec/features/cms/sns_post/twitter/approval_spec.rb @@ -0,0 +1,251 @@ +require 'spec_helper' + +describe "article_pages twitter post", type: :feature, dbscope: :example, js: true do + let(:site) { cms_site } + let(:node) { create :article_node_page } + let(:item) { create :article_page, cur_node: node, state: "closed" } + + let(:user) { cms_user } + let!(:user1) { create(:cms_test_user, group_ids: user.group_ids, cms_role_ids: user.cms_role_ids) } + + let(:show_path) { article_page_path site.id, node, item } + let(:edit_path) { edit_article_page_path site.id, node, item } + + let(:line_text_message) { unique_id } + + context "approve and publish" do + before do + site.twitter_username = unique_id + site.twitter_consumer_key = unique_id + site.twitter_consumer_secret = unique_id + site.twitter_access_token = unique_id + site.twitter_access_token_secret = unique_id + site.save! + end + + context "post none" do + it "#edit" do + capture_twitter_rest_client do |capture| + # edit + login_cms_user + visit edit_path + + ensure_addon_opened("#addon-cms-agents-addons-twitter_poster") + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.expired"), from: "item[twitter_auto_post]" + end + within "form#item-form" do + click_on I18n.t("ss.buttons.draft_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + visit show_path + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_no_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 0 + expect(capture.update.tweet).to eq nil + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 0 + + # send request + within ".mod-workflow-request" do + select I18n.t("mongoid.attributes.workflow/model/route.my_group"), from: "workflow_route" + click_on I18n.t("workflow.buttons.select") + click_on I18n.t("workflow.search_approvers.index") + end + + wait_for_cbox do + expect(page).to have_content(user1.long_name) + click_on user1.long_name + end + within ".mod-workflow-request" do + click_on I18n.t("workflow.buttons.request") + end + expect(page).to have_css(".mod-workflow-view dd", text: I18n.t("workflow.state.request")) + + # approve + login_user user1 + visit show_path + within ".mod-workflow-approve" do + expect(page).to have_no_css(".sns-post-confirm", text: I18n.t("cms.confirm.twitter_post_enabled")) + click_on I18n.t("workflow.buttons.approve") + end + within "#addon-workflow-agents-addons-approver" do + expect(page).to have_css("dd", text: I18n.t("ss.options.state.approve")) + end + within "#addon-cms-agents-addons-release" do + expect(page).to have_css("dd", text: I18n.t("ss.options.state.public")) + end + + login_cms_user + visit show_path + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_no_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 0 + expect(capture.update.tweet).to eq nil + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 0 + end + end + end + + context "post message" do + it "#edit" do + capture_twitter_rest_client do |capture| + # edit + login_cms_user + visit edit_path + + ensure_addon_opened("#addon-cms-agents-addons-twitter_poster") + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[twitter_auto_post]" + end + within "form#item-form" do + click_on I18n.t("ss.buttons.draft_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_no_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 0 + expect(capture.update.tweet).to eq nil + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 0 + + # send request + within ".mod-workflow-request" do + select I18n.t("mongoid.attributes.workflow/model/route.my_group"), from: "workflow_route" + click_on I18n.t("workflow.buttons.select") + click_on I18n.t("workflow.search_approvers.index") + end + + wait_for_cbox do + expect(page).to have_content(user1.long_name) + click_on user1.long_name + end + within ".mod-workflow-request" do + click_on I18n.t("workflow.buttons.request") + end + expect(page).to have_css(".mod-workflow-view dd", text: I18n.t("workflow.state.request")) + + # approve + login_user user1 + visit show_path + within ".mod-workflow-approve" do + expect(page).to have_css(".sns-post-confirm", text: I18n.t("cms.confirm.twitter_post_enabled")) + click_on I18n.t("workflow.buttons.approve") + end + within "#addon-workflow-agents-addons-approver" do + expect(page).to have_css("dd", text: I18n.t("ss.options.state.approve")) + end + within "#addon-cms-agents-addons-release" do + expect(page).to have_css("dd", text: I18n.t("ss.options.state.public")) + end + + login_cms_user + visit show_path + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 1 + expect(capture.update.tweet).to include(item.name) + expect(capture.update.tweet).to include(item.full_url) + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 1 + end + end + + # with branch page + it "#edit" do + capture_twitter_rest_client do |capture| + # create branch + login_cms_user + visit show_path + within "#addon-workflow-agents-addons-branch" do + click_on I18n.t("workflow.create_branch") + expect(page).to have_link item.name + click_on item.name + end + expect(page).to have_link I18n.t("ss.links.edit") + + # edit + click_on I18n.t("ss.links.edit") + ensure_addon_opened("#addon-cms-agents-addons-twitter_poster") + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[twitter_auto_post]" + end + within "form#item-form" do + click_on I18n.t("ss.buttons.draft_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_no_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 0 + expect(capture.update.tweet).to eq nil + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 0 + + # send request + within ".mod-workflow-request" do + select I18n.t("mongoid.attributes.workflow/model/route.my_group"), from: "workflow_route" + click_on I18n.t("workflow.buttons.select") + click_on I18n.t("workflow.search_approvers.index") + end + + wait_for_cbox do + expect(page).to have_content(user1.long_name) + click_on user1.long_name + end + within ".mod-workflow-request" do + click_on I18n.t("workflow.buttons.request") + end + expect(page).to have_css(".mod-workflow-view dd", text: I18n.t("workflow.state.request")) + + # approve + login_user user1 + visit show_path + within "#addon-workflow-agents-addons-branch" do + expect(page).to have_link item.name + click_on item.name + end + + within ".mod-workflow-approve" do + expect(page).to have_css(".sns-post-confirm", text: I18n.t("cms.confirm.twitter_post_enabled")) + click_on I18n.t("workflow.buttons.approve") + end + within "#addon-workflow-agents-addons-approver" do + expect(page).to have_css("dd", text: I18n.t("ss.options.state.approve")) + end + within "#addon-cms-agents-addons-release" do + expect(page).to have_css("dd", text: I18n.t("ss.options.state.public")) + end + + login_cms_user + visit show_path + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 1 + expect(capture.update.tweet).to include(item.name) + expect(capture.update.tweet).to include(item.full_url) + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 1 + end + end + end + end +end diff --git a/spec/features/cms/sns_post/twitter/basic_spec.rb b/spec/features/cms/sns_post/twitter/basic_spec.rb new file mode 100644 index 00000000000..2cbb3569654 --- /dev/null +++ b/spec/features/cms/sns_post/twitter/basic_spec.rb @@ -0,0 +1,246 @@ +require 'spec_helper' + +describe "article_pages twitter post", type: :feature, dbscope: :example, js: true do + let(:site) { cms_site } + let(:user) { cms_user } + let(:node) { create :article_node_page } + let(:item) { create :article_page, cur_node: node, state: "closed" } + + let(:new_path) { new_article_page_path site.id, node } + let(:show_path) { article_page_path site.id, node, item } + let(:edit_path) { edit_article_page_path site.id, node, item } + + let(:name) { "sample" } + + context "publish directly" do + before do + site.twitter_username = unique_id + site.twitter_consumer_key = unique_id + site.twitter_consumer_secret = unique_id + site.twitter_access_token = unique_id + site.twitter_access_token_secret = unique_id + site.save! + + login_cms_user + end + + context "post none" do + it "#new" do + capture_twitter_rest_client do |capture| + visit new_path + within "form#item-form" do + fill_in "item[name]", with: name + end + ensure_addon_opened("#addon-cms-agents-addons-twitter_poster") + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.expired"), from: "item[twitter_auto_post]" + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + visit current_path + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_no_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 0 + expect(capture.update.tweet).to eq nil + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 0 + end + end + + it "#edit" do + capture_twitter_rest_client do |capture| + visit edit_path + ensure_addon_opened("#addon-cms-agents-addons-twitter_poster") + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.expired"), from: "item[twitter_auto_post]" + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + visit show_path + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_no_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 0 + expect(capture.update.tweet).to eq nil + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 0 + end + end + end + + context "post message" do + it "#new" do + capture_twitter_rest_client do |capture| + visit new_path + within "form#item-form" do + fill_in "item[name]", with: name + end + ensure_addon_opened("#addon-cms-agents-addons-twitter_poster") + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[twitter_auto_post]" + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + wait_for_cbox do + have_css("#alertExplanation", text: I18n.t("cms.confirm.twitter_post_enabled")) + click_on I18n.t("ss.buttons.ignore_alert") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + visit current_path + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 1 + expect(capture.update.tweet).to include(name) + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 1 + end + end + + it "#edit" do + capture_twitter_rest_client do |capture| + visit edit_path + ensure_addon_opened("#addon-cms-agents-addons-twitter_poster") + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[twitter_auto_post]" + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + wait_for_cbox do + have_css("#alertExplanation", text: I18n.t("cms.confirm.twitter_post_enabled")) + click_on I18n.t("ss.buttons.ignore_alert") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + visit show_path + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 1 + expect(capture.update.tweet).to include(item.name) + expect(capture.update.tweet).to include(item.full_url) + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 1 + end + end + end + + context "post message add media files" do + let(:attach_file_path) { "#{Rails.root}/spec/fixtures/ss/file/keyvisual.gif" } + + it "#new" do + capture_twitter_rest_client do |capture| + visit new_path + within "form#item-form" do + fill_in "item[name]", with: name + end + + ensure_addon_opened("#addon-cms-agents-addons-file") + within "#addon-cms-agents-addons-file" do + wait_cbox_open do + click_on I18n.t("ss.buttons.upload") + end + end + wait_for_cbox do + attach_file "item[in_files][]", attach_file_path + wait_cbox_close do + click_button I18n.t("ss.buttons.attach") + end + end + within '#selected-files' do + click_on I18n.t("sns.image_paste") + end + + ensure_addon_opened("#addon-cms-agents-addons-twitter_poster") + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[twitter_auto_post]" + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + wait_for_cbox do + have_css("#alertExplanation", text: I18n.t("cms.confirm.twitter_post_enabled")) + click_on I18n.t("ss.buttons.ignore_alert") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + visit current_path + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 0 + expect(capture.update.tweet).to eq nil + expect(capture.update_with_media.count).to eq 1 + expect(capture.update_with_media.tweet).to include(name) + expect(Cms::SnsPostLog::Twitter.count).to eq 1 + end + end + + it "#edit" do + capture_twitter_rest_client do |capture| + visit edit_path + + ensure_addon_opened("#addon-cms-agents-addons-file") + within "#addon-cms-agents-addons-file" do + wait_cbox_open do + click_on I18n.t("ss.buttons.upload") + end + end + wait_for_cbox do + attach_file "item[in_files][]", attach_file_path + wait_cbox_close do + click_button I18n.t("ss.buttons.attach") + end + end + within '#selected-files' do + click_on I18n.t("sns.image_paste") + end + + ensure_addon_opened("#addon-cms-agents-addons-twitter_poster") + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[twitter_auto_post]" + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + wait_for_cbox do + have_css("#alertExplanation", text: I18n.t("cms.confirm.twitter_post_enabled")) + click_on I18n.t("ss.buttons.ignore_alert") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + visit show_path + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 0 + expect(capture.update.tweet).to eq nil + expect(capture.update_with_media.count).to eq 1 + expect(capture.update_with_media.tweet).to include(item.name) + expect(capture.update_with_media.tweet).to include(item.full_url) + expect(Cms::SnsPostLog::Twitter.count).to eq 1 + end + end + end + end +end diff --git a/spec/features/cms/sns_post/twitter/merge_spec.rb b/spec/features/cms/sns_post/twitter/merge_spec.rb new file mode 100644 index 00000000000..26b622d3b77 --- /dev/null +++ b/spec/features/cms/sns_post/twitter/merge_spec.rb @@ -0,0 +1,176 @@ +require 'spec_helper' + +describe "article_pages twitter post", type: :feature, dbscope: :example, js: true do + let(:site) { cms_site } + let(:user) { cms_user } + let(:node) { create :article_node_page } + let(:item) { create :article_page, cur_node: node, state: "closed" } + + let(:new_path) { new_article_page_path site.id, node } + let(:show_path) { article_page_path site.id, node, item } + + let(:name) { "sample" } + + context "merge and publish" do + before do + site.twitter_username = unique_id + site.twitter_consumer_key = unique_id + site.twitter_consumer_secret = unique_id + site.twitter_access_token = unique_id + site.twitter_access_token_secret = unique_id + site.save! + + login_cms_user + end + + context "post none" do + it "#edit" do + capture_twitter_rest_client do |capture| + visit show_path + within "#addon-workflow-agents-addons-branch" do + click_on I18n.t("workflow.create_branch") + expect(page).to have_link item.name + click_on item.name + end + + expect(page).to have_link I18n.t("ss.links.edit") + click_on I18n.t("ss.links.edit") + + ensure_addon_opened("#addon-cms-agents-addons-twitter_poster") + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.expired"), from: "item[twitter_auto_post]" + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + visit show_path + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_no_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 0 + expect(capture.update.tweet).to eq nil + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 0 + end + end + end + + context "post message" do + it "#edit" do + capture_twitter_rest_client do |capture| + visit show_path + within "#addon-workflow-agents-addons-branch" do + click_on I18n.t("workflow.create_branch") + expect(page).to have_link item.name + click_on item.name + end + + expect(page).to have_link I18n.t("ss.links.edit") + click_on I18n.t("ss.links.edit") + + ensure_addon_opened("#addon-cms-agents-addons-twitter_poster") + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[twitter_auto_post]" + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + wait_for_cbox do + have_css("#alertExplanation", text: I18n.t("cms.confirm.twitter_post_enabled")) + click_on I18n.t("ss.buttons.ignore_alert") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + visit show_path + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 1 + expect(capture.update.tweet).to include(item.name) + expect(capture.update.tweet).to include(item.full_url) + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 1 + end + end + + # master page already posted + it "#edit" do + capture_twitter_rest_client do |capture| + # first post + visit show_path + within "#addon-workflow-agents-addons-branch" do + click_on I18n.t("workflow.create_branch") + expect(page).to have_link item.name + click_on item.name + end + + expect(page).to have_link I18n.t("ss.links.edit") + click_on I18n.t("ss.links.edit") + + ensure_addon_opened("#addon-cms-agents-addons-twitter_poster") + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[twitter_auto_post]" + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + wait_for_cbox do + have_css("#alertExplanation", text: I18n.t("cms.confirm.twitter_post_enabled")) + click_on I18n.t("ss.buttons.ignore_alert") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + visit show_path + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 1 + expect(capture.update.tweet).to include(item.name) + expect(capture.update.tweet).to include(item.full_url) + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 1 + + # second post + visit show_path + within "#addon-workflow-agents-addons-branch" do + click_on I18n.t("workflow.create_branch") + expect(page).to have_link item.name + click_on item.name + end + + expect(page).to have_link I18n.t("ss.links.edit") + click_on I18n.t("ss.links.edit") + + ensure_addon_opened("#addon-cms-agents-addons-twitter_poster") + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.active")) + select I18n.t("ss.options.state.active"), from: "item[twitter_auto_post]" + end + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + visit show_path + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 1 + expect(capture.update.tweet).to include(item.name) + expect(capture.update.tweet).to include(item.full_url) + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 1 + end + end + end + end +end diff --git a/spec/features/cms/sns_post/twitter/release_page_spec.rb b/spec/features/cms/sns_post/twitter/release_page_spec.rb new file mode 100644 index 00000000000..ee7bdc6712b --- /dev/null +++ b/spec/features/cms/sns_post/twitter/release_page_spec.rb @@ -0,0 +1,235 @@ +require 'spec_helper' + +describe "article_pages twitter post", type: :feature, dbscope: :example, js: true do + let(:site) { cms_site } + let(:node) { create :article_node_page } + let(:item) { create :article_page, cur_node: node, state: "closed" } + + let(:user) { cms_user } + let!(:user1) { create(:cms_test_user, group_ids: user.group_ids, cms_role_ids: user.cms_role_ids) } + + let(:show_path) { article_page_path site.id, node, item } + let(:edit_path) { edit_article_page_path site.id, node, item } + + let(:release_date) { Time.zone.at(1.day.from_now.to_i) } + + context "publish at release_date" do + before do + site.twitter_username = unique_id + site.twitter_consumer_key = unique_id + site.twitter_consumer_secret = unique_id + site.twitter_access_token = unique_id + site.twitter_access_token_secret = unique_id + site.save! + + login_cms_user + end + + context "post none" do + it "#edit" do + capture_twitter_rest_client do |capture| + visit edit_path + ensure_addon_opened("#addon-cms-agents-addons-twitter_poster") + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.expired"), from: "item[twitter_auto_post]" + end + + ensure_addon_opened("#addon-cms-agents-addons-release_plan") + within "#addon-cms-agents-addons-release_plan" do + fill_in 'item[release_date]', with: release_date.strftime("%Y/%m/%d %H:%M") + end + + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + within "#addon-cms-agents-addons-release" do + expect(page).to have_css('dd', text: I18n.t('ss.state.ready')) + end + expect(capture.update.count).to eq 0 + expect(capture.update.tweet).to eq nil + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 0 + + Timecop.travel(release_date) do + job = Cms::Page::ReleaseJob.bind(site_id: node.site_id, node_id: node.id) + expect { job.perform_now }.to output.to_stdout + + login_cms_user + visit show_path + + within "#addon-cms-agents-addons-release" do + expect(page).to have_css('dd', text: I18n.t('ss.options.state.public')) + end + expect(capture.update.count).to eq 0 + expect(capture.update.tweet).to eq nil + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 0 + end + end + end + end + + context "post message_only_carousel" do + it "#edit" do + capture_twitter_rest_client do |capture| + visit edit_path + ensure_addon_opened("#addon-cms-agents-addons-twitter_poster") + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[twitter_auto_post]" + end + + ensure_addon_opened("#addon-cms-agents-addons-release_plan") + within "#addon-cms-agents-addons-release_plan" do + fill_in 'item[release_date]', with: release_date.strftime("%Y/%m/%d %H:%M") + end + + within "form#item-form" do + click_on I18n.t("ss.buttons.publish_save") + end + wait_for_cbox do + have_css("#alertExplanation", text: I18n.t("cms.confirm.twitter_post_enabled")) + click_on I18n.t("ss.buttons.ignore_alert") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + + within "#addon-cms-agents-addons-release" do + expect(page).to have_css('dd', text: I18n.t('ss.state.ready')) + end + expect(capture.update.count).to eq 0 + expect(capture.update.tweet).to eq nil + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 0 + + Timecop.travel(release_date) do + job = Cms::Page::ReleaseJob.bind(site_id: node.site_id, node_id: node.id) + expect { job.perform_now }.to output.to_stdout + + login_cms_user + visit show_path + + within "#addon-cms-agents-addons-release" do + expect(page).to have_css('dd', text: I18n.t('ss.options.state.public')) + end + expect(capture.update.count).to eq 1 + expect(capture.update.tweet).to include(item.name) + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 1 + end + end + end + + # master and approve + it "#edit" do + capture_twitter_rest_client do |capture| + # create branch + login_cms_user + visit show_path + within "#addon-workflow-agents-addons-branch" do + click_on I18n.t("workflow.create_branch") + expect(page).to have_link item.name + click_on item.name + end + expect(page).to have_link I18n.t("ss.links.edit") + + # edit + click_on I18n.t("ss.links.edit") + ensure_addon_opened("#addon-cms-agents-addons-twitter_poster") + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("select option[selected]", text: I18n.t("ss.options.state.expired")) + select I18n.t("ss.options.state.active"), from: "item[twitter_auto_post]" + end + + ensure_addon_opened("#addon-cms-agents-addons-release_plan") + within "#addon-cms-agents-addons-release_plan" do + fill_in 'item[release_date]', with: release_date.strftime("%Y/%m/%d %H:%M") + end + first("#addon-cms-agents-addons-release_plan").click + + within "form#item-form" do + click_on I18n.t("ss.buttons.draft_save") + end + expect(page).to have_css('#notice', text: I18n.t('ss.notice.saved')) + expect(capture.update.count).to eq 0 + expect(capture.update.tweet).to eq nil + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 0 + + # send request + within ".mod-workflow-request" do + select I18n.t("mongoid.attributes.workflow/model/route.my_group"), from: "workflow_route" + click_on I18n.t("workflow.buttons.select") + click_on I18n.t("workflow.search_approvers.index") + end + + wait_for_cbox do + expect(page).to have_content(user1.long_name) + click_on user1.long_name + end + within ".mod-workflow-request" do + click_on I18n.t("workflow.buttons.request") + end + expect(page).to have_css(".mod-workflow-view dd", text: I18n.t("workflow.state.request")) + + # approve + login_user user1 + visit show_path + within "#addon-workflow-agents-addons-branch" do + expect(page).to have_link item.name + click_on item.name + end + + within ".mod-workflow-approve" do + expect(page).to have_css(".sns-post-confirm", text: I18n.t("cms.confirm.twitter_post_enabled")) + click_on I18n.t("workflow.buttons.approve") + end + within "#addon-workflow-agents-addons-approver" do + expect(page).to have_css("dd", text: I18n.t("ss.options.state.approve")) + end + within "#addon-cms-agents-addons-release" do + expect(page).to have_css("dd", text: I18n.t("ss.options.state.ready")) + end + + visit show_path + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_no_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 0 + expect(capture.update.tweet).to eq nil + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 0 + + + Timecop.travel(release_date) do + job = Cms::Page::ReleaseJob.bind(site_id: node.site_id, node_id: node.id) + expect { job.perform_now }.to output.to_stdout + + login_cms_user + visit show_path + + within "#addon-cms-agents-addons-release" do + expect(page).to have_css('dd', text: I18n.t('ss.options.state.public')) + end + within "#addon-cms-agents-addons-twitter_poster" do + expect(page).to have_css("dd", text: "https://twitter.com/user_screen_id/status/twitter_id") + end + expect(capture.update.count).to eq 1 + expect(capture.update.tweet).to include(item.name) + expect(capture.update_with_media.count).to eq 0 + expect(capture.update_with_media.tweet).to eq nil + expect(Cms::SnsPostLog::Twitter.count).to eq 1 + end + end + end + end + end +end diff --git a/spec/support/cms/line_poster.rb b/spec/support/cms/line_poster.rb new file mode 100644 index 00000000000..27ccda598b3 --- /dev/null +++ b/spec/support/cms/line_poster.rb @@ -0,0 +1,11 @@ +def capture_line_bot_client + capture = OpenStruct.new + + capture.broadcast = OpenStruct.new(count: 0) + allow_any_instance_of(Line::Bot::Client).to receive(:broadcast) do |*args| + capture.broadcast.count += 1 + capture.broadcast.messages = args[1] + OpenStruct.new(code: "200", body: "{}") + end + yield(capture) +end diff --git a/spec/support/cms/twitter_poster.rb b/spec/support/cms/twitter_poster.rb new file mode 100644 index 00000000000..dccc3980132 --- /dev/null +++ b/spec/support/cms/twitter_poster.rb @@ -0,0 +1,33 @@ +def capture_twitter_rest_client + capture = OpenStruct.new + + capture.update_with_media = OpenStruct.new(count: 0) + allow_any_instance_of(Twitter::REST::Client).to receive(:update_with_media) do |*args| + capture.update_with_media.count += 1 + capture.update_with_media.tweet = args[1] + capture.update_with_media.media_files = args[2] + OpenStruct.new(id: "twitter_id") + end + + capture.update = OpenStruct.new(count: 0) + allow_any_instance_of(Twitter::REST::Client).to receive(:update) do |*args| + capture.update.count += 1 + capture.update.tweet = args[1] + OpenStruct.new(id: "twitter_id") + end + + capture.user = OpenStruct.new(count: 0) + allow_any_instance_of(Twitter::REST::Client).to receive(:user) do |*args| + capture.user.count += 1 + OpenStruct.new(screen_name: "user_screen_id") + end + + capture.destroy_status = OpenStruct.new(count: 0) + allow_any_instance_of(Twitter::REST::Client).to receive(:destroy_status) do |*args| + capture.destroy_status.count += 1 + capture.destroy_status.post_id = args[1] + true + end + + yield(capture) +end