Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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
You can’t perform that action at this time.