Skip to content

Instantly share code, notes, and snippets.

@cat-in-136
Forked from diffshare/replace-from-cybozu-to-redmine.rb
Last active December 8, 2018 22:55
Show Gist options
  • Save cat-in-136/a7ec320939f35812a64ac4e35e2a947b to your computer and use it in GitHub Desktop.
Save cat-in-136/a7ec320939f35812a64ac4e35e2a947b to your computer and use it in GitHub Desktop.
replace-from-cybozu-to-redmine.rb
# Created by https://www.gitignore.io/api/vim,emacs,rails
### Emacs ###
# -*- mode: gitignore; -*-
*~
\#*\#
/.emacs.desktop
/.emacs.desktop.lock
*.elc
auto-save-list
tramp
.\#*
# Org-mode
.org-id-locations
*_archive
# flymake-mode
*_flymake.*
# eshell files
/eshell/history
/eshell/lastdir
# elpa packages
/elpa/
# reftex files
*.rel
# AUCTeX auto folder
/auto/
# cask packages
.cask/
dist/
# Flycheck
flycheck_*.el
# server auth directory
/server/
# projectiles files
.projectile
projectile-bookmarks.eld
# directory configuration
.dir-locals.el
# saveplace
places
# url cache
url/cache/
# cedet
ede-projects.el
# smex
smex-items
# company-statistics
company-statistics-cache.el
# anaconda-mode
anaconda-mode/
### Rails ###
*.rbc
capybara-*.html
.rspec
/log
/tmp
/db/*.sqlite3
/db/*.sqlite3-journal
/public/system
/coverage/
/spec/tmp
*.orig
rerun.txt
pickle-email-*.html
# TODO Comment out this rule if you are OK with secrets being uploaded to the repo
config/initializers/secret_token.rb
# Only include if you have production secrets in this file, which is no longer a Rails default
# config/secrets.yml
# dotenv
# TODO Comment out this rule if environment variables can be committed
.env
## Environment normalization:
/.bundle
/vendor/bundle
# these should all be checked in to normalize the environment:
# Gemfile.lock, .ruby-version, .ruby-gemset
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
.rvmrc
# if using bower-rails ignore default bower_components path bower.json files
/vendor/assets/bower_components
*.bowerrc
bower.json
# Ignore pow environment settings
.powenv
# Ignore Byebug command history file.
.byebug_history
### Vim ###
# swap
.sw[a-p]
.*.sw[a-p]
# session
Session.vim
# temporary
.netrwhist
# auto-generated tag files
tags
# End of https://www.gitignore.io/api/vim,emacs,rails
# $ rails r ./replace-from-cybozu-to-redmine.rb
require "io/console"
require "readline"
require "net/http" if ENV["CYBOZU_COOKIE_HACK"]
require "mimemagic"
#
# RailsのGemfileで以下が必要
require "oauth"
EMOJI_REGEX = /[^\u0000-\uFFFF]/
consumer_key = ENV["CYBOZU_CONSUMER_KEY"] || Readline.readline("Consumer Key:") # cybozuliveの開発者登録
consumer_secret = ENV["CYBOZU_CONSUMER_SECRET"] || Readline.readline("Consumer Secret:")
consumer = OAuth::Consumer.new(
consumer_key,
consumer_secret,
:site => "https://api.cybozulive.com",
:request_token_url => "https://api.cybozulive.com/oauth/initiate",
:access_token_url => "https://api.cybozulive.com/oauth/token",
)
x_auth_username = ENV["CYBOZU_LOGIN_USER"] || Readline.readline("Cybozu Live メールアドレス:") # 自分のID/PW
x_auth_password = ENV["CYBOZU_LOGIN_PASS"] || STDIN.noecho { Readline.readline("Cybozu Live パスワード:").tap { puts } }
MISC_CONFIG = (ENV.include?("MISC_CONFIG") && File.exist?(ENV["MISC_CONFIG"]))?
YAML.load(File.open(ENV["MISC_CONFIG"], "r")) :
nil
ATTACH_CACHE_DIR = ((MISC_CONFIG)? MISC_CONFIG["ATTACH_CACHE_DIR"] : nil) || ENV["ATTACH_CACHE_DIR"]
puts <<-EOS
Consumer Key: #{consumer_key}
Consumer Secret: #{consumer_secret}
Cybozu Live メールアドレス: #{x_auth_username}
Cybozu Live パスワード: #{"*" * x_auth_password.length}
EOS
puts "添付ファイルキャッシュフォルダ: #{ATTACH_CACHE_DIR}" if ATTACH_CACHE_DIR
raise SystemExit unless Readline.readline("OK? [yn]:") =~ /^y$/i
access_token = consumer.get_access_token(
nil,
{},
{
:x_auth_mode => "client_auth",
:x_auth_username => x_auth_username,
:x_auth_password => x_auth_password,
}
)
def download_file(access_token, entry_id, cache_file_path)
Dir.mkdir(File.dirname(cache_file_path)) unless File.directory?(File.dirname(cache_file_path))
file_response = access_token.get "https://api.cybozulive.com/api/fileDownload/V2?id=#{entry_id}"
if file_response.is_a? Net::HTTPSuccess
File.open(cache_file_path, "wb") { |f| f << file_response.body }
else
File.open(cache_file_path + ".error.json", "wb") { |f| f << file_response.to_json }
end
if ENV["CYBOZU_COOKIE_HACK"] and not file_response.is_a? Net::HTTPSuccess
if entry_id =~ /\AGROUP,1:(\d+),CABINET,1:(\d+)\Z/
group_id, cabinet_id = $1, $2
# https://cybozulive.com/1_%GROUP_ID%/gwCabinet/downloadFileDirect?cid=%CABINET_ID%
Net::HTTP.start("cybozulive.com", 443, :use_ssl => true) do |https|
response = https.get("/1_#{group_id}/gwCabinet/downloadFileDirect?cid=#{cabinet_id}",
"Host" => "cybozulive.com",
"User-Agent" => "Mozilla/5.0",
"Cookie" => ENV["CYBOZU_COOKIE_HACK"])
if response.is_a? Net::HTTPSuccess
File.open(cache_file_path, "wb") { |f| f << response.body }
else
File.open(cache_file_path + ".error2.json", "wb") { |f| f << response.to_json }
end
end
end
end
end
USER_DATA_CACHE = User.all.to_a.freeze
def find_user_from_cybozu_id(who_id)
user = nil
if MISC_CONFIG && MISC_CONFIG["users"]
who = MISC_CONFIG["users"][who_id]
case who
when Numeric then user = USER_DATA_CACHE.find { |v| v.id == who }
when String then user = USER_DATA_CACHE.find { |v| v.login == who }
end
end
yield user if user
end
def heart_bluk_update(message, hearted_users)
return if hearted_users.empty?
hearts = hearted_users.uniq.map { |user| Heart.new(:heartable => message, :user => user, :created_at => message.created_on, :updated_at => message.updated_on) }
if (Heart.methods.include? :import) # activerecord-import
Heart.import(hearts)
else
hearts.each { |heart| heart.save }
end
end
response = access_token.get "https://api.cybozulive.com/api/group/V2"
groups = Nokogiri.XML response.body
groups = groups.css("feed > entry")
groups.each_with_index do |v, index|
puts "#{index + 1}. #{v.at(:id).text} #{v.at(:title).text}"
end
group_index = Readline.readline("Group? [1-#{groups.length}]:").to_i
group_id = groups[group_index - 1].at(:id)
id = group_id.text[6..-1]
# 破壊的テストなので、よろしく
#Board.destroy_all
#Message.destroy_all
board = Project.first.boards.build
board.name = "サイボウズ: #{groups[group_index - 1].at(:title).text}"
board.description = groups[group_index - 1].at(:summary).try!(:text) || "(説明なし)"
board.save
1.step do |board_page|
board_start_index = 100 * (board_page - 1)
response = access_token.get "https://api.cybozulive.com/api/board/V2?group=#{id}&max-results=100&start-index=#{board_start_index}"
board_feed = Nokogiri.XML response.body
break if board_feed.css("entry").count == 0
board_feed.css("entry").each do |entry|
board_id = entry.at("id").text
id = board_id.split(":")[2]
message = board.messages.new
message.subject = entry.at(:title).text
message.content = entry.at(:summary).try!(:text)
message.content = "(コンテンツなし)" if message.content.blank?
message.content = message.content.gsub(EMOJI_REGEX) { |v| "&#x%x;" % [ v.ord ] } if MISC_CONFIG && MISC_CONFIG["escape_emoji"]
message.content << "\n\nImport from: #{entry.at(:'link[rel=alternate]').attribute('href')}" if MISC_CONFIG && MISC_CONFIG["add_import_source_to_content"]
find_user_from_cybozu_id(entry.at(:author).try!(:at, :uri).try!(:text)) do |user|
message.author = user
end
message.created_on = entry.at(:"cbl|published").text
message.updated_on = entry.at(:updated).text
unless message.save
raise :error
end
if ATTACH_CACHE_DIR
entry.css("cbl|attachment").each do |attachment|
container = message
file_name = attachment.attribute("fileName").to_s
entry_id = attachment.attribute("entryId").to_s
content_type = attachment.attribute("type").to_s
cache_file_path = File.join(ATTACH_CACHE_DIR, entry_id.gsub(/:/, "_"), file_name)
download_file(access_token, entry_id, cache_file_path) unless File.exist?(cache_file_path)
if File.exist?(cache_file_path) and File.size(cache_file_path) > 0
File.open(cache_file_path, "rb") do |f|
f.flock(File::LOCK_SH)
content_type = MimeMagic.by_magic(f) if File.basename(cache_file_path) == "photo.jpg"
Attachment.create!(
:file => ActionDispatch::Http::UploadedFile.new(:tempfile => f, :filename => file_name, :type => content_type),
:author => message.author || User.first,
:container => container,
)
end
end
end if board_feed.namespaces.include?("xmlns:cbl")
end
if Redmine::Plugin.installed?(:redmine_hearts) && MISC_CONFIG && MISC_CONFIG["users"]
good_response = access_token.get "https://api.cybozulive.com/api/good/V2?id=#{entry.at(:id).text}"
good_feed = Nokogiri.XML good_response.body
hearted_users = []
if good_feed.css("entry cblGood|set")[0].text == "true"
find_user_from_cybozu_id(good_feed.css("feed > author > uri")[0].text) do |user|
hearted_users << user
end
end
good_feed.css("entry cbl|who").each do |who|
find_user_from_cybozu_id(who.attribute("id").to_s) do |user|
hearted_users << user
end
end
heart_bluk_update(message, hearted_users)
end
1.step do |comment_page|
comment_start_index = 100 * (comment_page - 1)
comment_response = access_token.get "https://api.cybozulive.com/api/comment/V2?entry=#{board_id}&max-results=100&start-index=#{comment_start_index}"
comment_feed = Nokogiri.XML comment_response.body
break if comment_feed.css("entry").count == 0
comment_feed.css("entry").each do |comment|
reply = board.messages.new
reply.subject = comment.attribute("sequence").to_s # "Re: #{message.subject}"
reply.parent = message
reply.content = comment.at(:summary).try!(:text)
reply.content = "(コンテンツなし)" if reply.content.blank?
reply.content = reply.content.gsub(EMOJI_REGEX) { |v| "&#x%x;" % [ v.ord ] } if MISC_CONFIG && MISC_CONFIG["escape_emoji"]
reply.content = "`>#{comment.at(:"cblCmnt|replyTo").text}`への返信\n\n#{reply.content}" if comment.at(:"cblCmnt|replyTo") && MISC_CONFIG && MISC_CONFIG["add_reply_to"]
reply.content << "\n\nImport from: #{comment.at(:'link[rel=alternate]').attribute('href')}" if MISC_CONFIG && MISC_CONFIG["add_import_source_to_content"]
find_user_from_cybozu_id(comment.at(:author).try!(:at, :uri).try!(:text)) do |user|
reply.author = user
end
reply.created_on = comment.at(:updated).text
reply.updated_on = comment.at(:updated).text
#next if reply.board.blank?
unless reply.save
raise :error
end
comment.css("cbl|attachment").each do |attachment|
container = reply
file_name = attachment.attribute("fileName").to_s
entry_id = attachment.attribute("entryId").to_s
content_type = attachment.attribute("type").to_s
cache_file_path = File.join(ATTACH_CACHE_DIR, entry_id.gsub(/:/, "_"), file_name)
download_file(access_token, entry_id, cache_file_path) unless File.exist?(cache_file_path)
if File.exist?(cache_file_path) and File.size(cache_file_path) > 0
File.open(cache_file_path, "rb") do |f|
f.flock(File::LOCK_SH)
content_type = MimeMagic.by_magic(f) if File.basename(cache_file_path) == "photo.jpg"
Attachment.create!(
:file => ActionDispatch::Http::UploadedFile.new(:tempfile => f, :filename => file_name, :type => content_type),
:author => message.author || User.first,
:container => container,
)
end
end
end if comment_feed.namespaces.include?("xmlns:cbl")
if comment.at(:"cblGood|count").text.to_i > 0
if Redmine::Plugin.installed?(:redmine_hearts) && MISC_CONFIG && MISC_CONFIG["users"]
good_response = access_token.get "https://api.cybozulive.com/api/good/V2?id=#{comment.at(:id).text}"
good_feed = Nokogiri.XML good_response.body
hearted_users = []
if good_feed.css("entry cblGood|set")[0].text == "true"
find_user_from_cybozu_id(good_feed.css("feed > author > uri")[0].text) do |user|
hearted_users << user
end
end
good_feed.css("entry cbl|who").each do |who|
find_user_from_cybozu_id(who.attribute("id").to_s) do |user|
hearted_users << user
end
end
heart_bluk_update(reply, hearted_users)
end
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment