Forked from diffshare/replace-from-cybozu-to-redmine.rb
Last active
December 8, 2018 22:55
-
-
Save cat-in-136/a7ec320939f35812a64ac4e35e2a947b to your computer and use it in GitHub Desktop.
replace-from-cybozu-to-redmine.rb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# $ 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