Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 🎸 ダイレクトメッセージのデータをスプレッドシートに送り込む #200

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
feat: 🎸 ダイレクトメッセージのデータをスプレッドシートに送り込む
nikukyugamer committed Jun 27, 2022

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 4ef8ac8ccb92073c9453b7392ee0faafcc5f1cad
6 changes: 6 additions & 0 deletions app/models/direct_message.rb
Original file line number Diff line number Diff line change
@@ -7,6 +7,12 @@ class DirectMessage < ApplicationRecord

validates :id_number, uniqueness: true

def self.for_spreadsheet
to_gensosenkyo
.order(messaged_at: :asc)
.order(id_number: :asc)
end

# self.user と同義
def sender
User.find_by(id_number: sender_id_number)
68 changes: 58 additions & 10 deletions app/services/sheets/write_and_update/direct_messages.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,64 @@
module Sheets
module WriteAndUpdate
class DirectMessages
def self.exec
direct_messages = DirectMessage.for_spreadsheet

direct_messages.each_slice(100).with_index do |dm_100, index_on_hundred|
prepared_written_data_by_array_in_hash = []

dm_100.each_with_index do |dm, i|
inserted_hash = {}

inserted_hash['screen_name'] = dm.user.screen_name
inserted_hash['dm_id'] = dm.id_number.to_s
inserted_hash['日時'] = dm.messaged_at.strftime('%Y/%m/%d %H:%M:%S').to_s
inserted_hash['内容'] = dm.content_text
# この行のコストが高い
inserted_hash['suggested_names'] = NaturalLanguage::SuggestCharacterNames.exec(dm) # Array

prepared_written_data_by_array_in_hash << inserted_hash
end

two_digit_number = format('%02<number>d', number: index_on_hundred + 1)
sheet_name = "集計_#{two_digit_number}"

written_data = []

prepared_written_data_by_array_in_hash.each_with_index do |written_data_hash, index|
row = []

# TODO: 取得漏れには 10001 始まりを付与したい
id_on_sheet = (index_on_hundred * 100) + (index + 1)

# TODO: ハードコーディングをしたくない
row[0] = id_on_sheet
row[1] = written_data_hash['screen_name']
row[2] = written_data_hash['dm_id']
row[3] = written_data_hash['日時']
row[10] = written_data_hash['内容']
row[49] = written_data_hash['suggested_names'] # 50列目 (AX)
row[199] = '' # 200列目 (GR) を表示させるために空文字を入れる

row.flatten! # suggested_names は長さが不定なので flatten する

written_data << row
end

# suggested_names を最初に全削除する
SheetData.write_rows(
sheet_id: ENV.fetch('COUNTING_DIRECT_MESSAGES_SHEET_ID', nil),
range: "#{sheet_name}!AX2:GR101",
values: [[''] * 50] * 100 # 100行分の空文字を入れる
)

SheetData.write_rows(
sheet_id: ENV.fetch('COUNTING_DIRECT_MESSAGES_SHEET_ID', nil),
range: "#{sheet_name}!A2", # 始点
values: written_data
)
end
end
end
end
end

# DM
# dms = DirectMessage.to_gensosenkyo
# dm = dms.first
# dm.messaged_at
# dm.content_text
# dm.user.screen_name
# dm.user.name
# id(自動) 送信者(自動) 内容(自動) キャラ1 キャラ2 キャラ3 ツイ見られない?(自動) 備考 要レビュー? 返信 or チェック済み? 全終了? ドロップダウン用配列(触らない)
# DM は言語が取得できない
12 changes: 6 additions & 6 deletions clasp/gensosenkyo/ZzzColumnNames.ts
Original file line number Diff line number Diff line change
@@ -39,15 +39,15 @@ namespace ZzzColumnNames {
'screen_name',
'dm_id',
'日時',
'DMが見られない?',
'備考',
'要レビュー?',
'二次チェック済み?',
'対応済み?',
'全終了?',
'DMが見られない?',
'集計対象外?',
'対応済み?',
'二次チェック済?',
'種類', // ZzzDataValidation.setDataValidationDirectMessageTypes
'内容',
'種類',
'備考',
'要レビュー?',
'キャラ1 or 作品名',
'キャラ2 or 協力攻撃名',
'キャラ3',
39 changes: 30 additions & 9 deletions clasp/gensosenkyo/ZzzConditionalFormats.ts
Original file line number Diff line number Diff line change
@@ -46,8 +46,8 @@ namespace ZzzConditionalFormats {
}, '「条件付き書式」をクリアしました')
}

export const setInitToIsAllCompletedColumn = (sheet: GoogleAppsScript.Spreadsheet.Sheet) => {
const colNameToNumber = ZzzColumnNames.colNameToNumber()
export const setInitToIsAllCompletedColumn = (sheet: GoogleAppsScript.Spreadsheet.Sheet, category = '') => {
const colNameToNumber = ZzzColumnNames.colNameToNumber(category)

const requiredReviewColumnNumber = colNameToNumber['要レビュー?']
const requiredReviewColumnAlphabet = ZzzConverters.convertColumnNumberToAlphabet(requiredReviewColumnNumber)
@@ -81,8 +81,8 @@ namespace ZzzConditionalFormats {
)
}

export const setInitToIsRequiredReview = (sheet: GoogleAppsScript.Spreadsheet.Sheet) => {
const colNameToNumber = ZzzColumnNames.colNameToNumber()
export const setInitToIsRequiredReview = (sheet: GoogleAppsScript.Spreadsheet.Sheet, category = '') => {
const colNameToNumber = ZzzColumnNames.colNameToNumber(category)

const range = ZzzCellOperations.getRangeSpecificColumnRow2ToRow101(
colNameToNumber['要レビュー?'],
@@ -96,8 +96,8 @@ namespace ZzzConditionalFormats {
)
}

export const setInitToIsCompletedSecondCheck = (sheet: GoogleAppsScript.Spreadsheet.Sheet) => {
const colNameToNumber = ZzzColumnNames.colNameToNumber()
export const setInitToIsCompletedSecondCheck = (sheet: GoogleAppsScript.Spreadsheet.Sheet, category = '') => {
const colNameToNumber = ZzzColumnNames.colNameToNumber(category)

const range = ZzzCellOperations.getRangeSpecificColumnRow2ToRow101(
colNameToNumber['二次チェック済?'],
@@ -117,11 +117,32 @@ namespace ZzzConditionalFormats {
)
}

export const setInitToIsCompletedFavorite = (sheet: GoogleAppsScript.Spreadsheet.Sheet) => {
const colNameToNumber = ZzzColumnNames.colNameToNumber()
export const setInitToIsCompletedFavorite = (sheet: GoogleAppsScript.Spreadsheet.Sheet, category = '') => {
const colNameToNumber = ZzzColumnNames.colNameToNumber(category)

const range = ZzzCellOperations.getRangeSpecificColumnRow2ToRow101(
colNameToNumber['ふぁぼ済?'],
colNameToNumber['ふぁぼ済?'], // DMでは'対応済み?'
sheet
)
ZzzConditionalFormats.setColorToRangeInSpecificCondition(
range,
sheet,
'TRUE',
'#ccffcc' // Red
)
ZzzConditionalFormats.setColorToRangeInSpecificCondition(
range,
sheet,
'FALSE',
'#ffc0cb' // Red
)
}

export const setInitToIsCompletedDMResponse = (sheet: GoogleAppsScript.Spreadsheet.Sheet, category = 'directMessage') => {
const colNameToNumber = ZzzColumnNames.colNameToNumber(category)

const range = ZzzCellOperations.getRangeSpecificColumnRow2ToRow101(
colNameToNumber['対応済み?'],
sheet
)
ZzzConditionalFormats.setColorToRangeInSpecificCondition(
5 changes: 2 additions & 3 deletions clasp/gensosenkyo/ZzzDataValidation.ts
Original file line number Diff line number Diff line change
@@ -27,8 +27,7 @@ namespace ZzzDataValidation {
return sheet.getRange(rowNumber, 50, 1, 151)
}

export const setDataValidationDirectMessageTypes = (sheetName: string, columnNumber: number, destroyWord: string = '') => {
const sheet = ZzzSheetOperations.changeActiveSheetTo(sheetName)
export const setDataValidationDirectMessageTypes = (sheet: GoogleAppsScript.Spreadsheet.Sheet, columnNumber: number, destroyWord: string = '') => {
const startRowNumber = 2
const endRowNumber = 101

@@ -54,6 +53,6 @@ namespace ZzzDataValidation {
'ボ・開票イラスト',
'ボ・推し台詞',
'ボ・選挙運動',
'その他',
'票に関係ない',
]
}
64 changes: 64 additions & 0 deletions clasp/gensosenkyo/appForDirectMessages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
const mainForDirectMessages = () => {
// createTweetCountingSheets.destroyAllSheets()

// NOTE: 約6分かかる
createTweetCountingSheets.createAllSheets()

ZzzCommonScripts.showStartAndEndLogger(() => {
createTweetCountingSheets.setColumnNames('directMessage')
}, '列名を入力する')

ZzzCommonScripts.showStartAndEndLogger(() => {
createTweetCountingSheets.freezeFirstRowAndFirstColumn()
}, '一行目 および 一列目 を固定をする')

ZzzCommonScripts.showStartAndEndLogger(() => {
createTweetCountingSheets.setColumnWidths('directMessage')
}, '列幅を調整する')

ZzzCommonScripts.showStartAndEndLogger(() => {
createTweetCountingSheets.setBanpeis()
}, '102行目の各セルに "@" を入れる')

// 保護設定を全削除(やや重い処理)
ZzzSheetOperations.removeAllProtectedCellsOnAllSheets()

// やや重い処理
ZzzCommonScripts.showStartAndEndLogger(() => {
createTweetCountingSheets.createCheckBoxes('directMessage')
}, 'チェックボックスを作成する')

ZzzCommonScripts.showStartAndEndLogger(() => {
createTweetCountingSheets.setRappings('directMessage')
}, '「ラッピング」の形式を設定する')

// 「条件付き書式」を全削除
ZzzConditionalFormats.clearConditionalFormatsOnAllSheets()

// NOTE: 冪等ではない(追記となる)
ZzzCommonScripts.showStartAndEndLogger(() => {
// FIXME: 列がズレている
createTweetCountingSheets.setDefaultConditionalFormats('directMessage')
}, '「条件付き書式」を設定する')

// NOTE: 冪等ではない(追記となる)
ZzzCommonScripts.showStartAndEndLogger(() => {
createTweetCountingSheets.setGrayBackGroundInSpecificCondition('directMessage')
}, '(条件付き書式)特定のセルが条件を満たしたら行を灰色に塗る')

// サジェスト用に「入力規則」を設定する(重い)
createTweetCountingSheets.setDataValidationsForSuggestions('directMessage')

// 「種類」に「入力規則」を与える
const colNameToNumber = ZzzColumnNames.colNameToNumber('directMessage')

ZzzSheetOperations.applyFunctionToAllCountingSheets(
(sheet: GoogleAppsScript.Spreadsheet.Sheet) => {
ZzzDataValidation.setDataValidationDirectMessageTypes(
sheet,
colNameToNumber['種類']
)
},
'「種類」の「入力規則」を設定する'
)
}
83 changes: 54 additions & 29 deletions clasp/gensosenkyo/createTweetCountingSheets.ts
Original file line number Diff line number Diff line change
@@ -37,28 +37,36 @@ namespace createTweetCountingSheets {
)
}

export const setColumnWidths = () => {
const colNameToNumber = ZzzColumnNames.colNameToNumber()
export const setColumnWidths = (category = '') => {
const colNameToNumber = ZzzColumnNames.colNameToNumber(category)

ZzzSheetOperations.applyFunctionToAllCountingSheets(
(sheet: GoogleAppsScript.Spreadsheet.Sheet) => {
sheet.setColumnWidth(colNameToNumber['ID'], 40)
sheet.setColumnWidth(colNameToNumber['screen_name'], 30)
sheet.setColumnWidth(colNameToNumber['tweet_id'], 50)
sheet.setColumnWidth(colNameToNumber['日時'], 30)
sheet.setColumnWidth(colNameToNumber['URL'], 30)
sheet.setColumnWidth(colNameToNumber['別ツイ'], 40)
sheet.setColumnWidth(colNameToNumber['全終了?'], 40)
sheet.setColumnWidth(colNameToNumber['ツイ見られない?'], 120)
sheet.setColumnWidth(colNameToNumber['集計対象外?'], 90)
sheet.setColumnWidth(colNameToNumber['ふぁぼ済?'], 90)
sheet.setColumnWidth(colNameToNumber['二次チェック済?'], 130)
sheet.setColumnWidth(colNameToNumber['内容'], 200)
sheet.setColumnWidth(colNameToNumber['備考'], 100)
sheet.setColumnWidth(colNameToNumber['要レビュー?'], 90)
sheet.setColumnWidth(colNameToNumber['キャラ1 or 作品名'], 140)
sheet.setColumnWidth(colNameToNumber['キャラ2 or 協力攻撃名'], 140)
sheet.setColumnWidth(colNameToNumber['キャラ3'], 140)

if (category === 'directMessage') {
sheet.setColumnWidth(colNameToNumber['内容'], 300)
sheet.setColumnWidth(colNameToNumber['dm_id'], 50)
sheet.setColumnWidth(colNameToNumber['DMが見られない?'], 120)
sheet.setColumnWidth(colNameToNumber['対応済み?'], 90)
} else {
sheet.setColumnWidth(colNameToNumber['内容'], 200)
sheet.setColumnWidth(colNameToNumber['tweet_id'], 50)
sheet.setColumnWidth(colNameToNumber['URL'], 30)
sheet.setColumnWidth(colNameToNumber['別ツイ'], 40)
sheet.setColumnWidth(colNameToNumber['ツイ見られない?'], 120)
sheet.setColumnWidth(colNameToNumber['ふぁぼ済?'], 90)
}
},
'列幅を指定しました'
)
@@ -100,19 +108,25 @@ namespace createTweetCountingSheets {
}

// 既存データを上書きする破壊的メソッドなので注意する
export const createCheckBoxes = () => {
const colNameToNumber = ZzzColumnNames.colNameToNumber()
export const createCheckBoxes = (category = '') => {
const colNameToNumber = ZzzColumnNames.colNameToNumber(category)

ZzzSheetOperations.applyFunctionToAllCountingSheets(
(sheet: GoogleAppsScript.Spreadsheet.Sheet) => {
const requiredCheckboxColumnNumbers = [
colNameToNumber['ツイ見られない?'],
colNameToNumber['集計対象外?'],
colNameToNumber['ふぁぼ済?'],
colNameToNumber['二次チェック済?'],
colNameToNumber['要レビュー?'],
]

if (category === 'directMessage') {
requiredCheckboxColumnNumbers.push(colNameToNumber['対応済み?'])
requiredCheckboxColumnNumbers.push(colNameToNumber['DMが見られない?'])
} else {
requiredCheckboxColumnNumbers.push(colNameToNumber['ふぁぼ済?'])
requiredCheckboxColumnNumbers.push(colNameToNumber['ツイ見られない?'])
}

requiredCheckboxColumnNumbers.forEach(requiredCheckboxColumnNumber => {
const range = ZzzCellOperations.getRangeSpecificColumnRow2ToRow101(requiredCheckboxColumnNumber, sheet)

@@ -124,19 +138,22 @@ namespace createTweetCountingSheets {
}

// 表示形式 -> ラッピング -> はみ出す | 折り返す | 切り詰める
export const setRappings = () => {
const colNameToNumber = ZzzColumnNames.colNameToNumber()
export const setRappings = (category = '') => {
const colNameToNumber = ZzzColumnNames.colNameToNumber('directMessage')

ZzzSheetOperations.applyFunctionToAllCountingSheets(
(sheet: GoogleAppsScript.Spreadsheet.Sheet) => {
const kiritsumeruColumnNumbers = [
colNameToNumber['screen_name'],
colNameToNumber['tweet_id'],
colNameToNumber['日時'],
colNameToNumber['URL'],
colNameToNumber['別ツイ'],
]

if (category !== 'directMessage') {
kiritsumeruColumnNumbers.push(colNameToNumber['別ツイ']) // DMでは存在しないカラム
kiritsumeruColumnNumbers.push(colNameToNumber['tweet_id']) // DMでは存在しないカラム
kiritsumeruColumnNumbers.push(colNameToNumber['URL']) // DMでは存在しないカラム
}

kiritsumeruColumnNumbers.forEach(requiredColumnNumber => {
const range = ZzzCellOperations.getRangeSpecificColumnRow2ToRow101(requiredColumnNumber, sheet)

@@ -158,30 +175,34 @@ namespace createTweetCountingSheets {
)
}

export const setDefaultConditionalFormats = () => {
const colNameToNumber = ZzzColumnNames.colNameToNumber()

export const setDefaultConditionalFormats = (category = '') => {
ZzzSheetOperations.applyFunctionToAllCountingSheets(
(sheet: GoogleAppsScript.Spreadsheet.Sheet) => {
// 「全終了?」列
ZzzConditionalFormats.setInitToIsAllCompletedColumn(sheet)
// FIXME:
ZzzConditionalFormats.setInitToIsAllCompletedColumn(sheet, category)

// 「要レビュー?」列
ZzzConditionalFormats.setInitToIsRequiredReview(sheet)
ZzzConditionalFormats.setInitToIsRequiredReview(sheet, category)

// 「二次チェック済?」列
ZzzConditionalFormats.setInitToIsCompletedSecondCheck(sheet)

// 「ふぁぼ済?」列
ZzzConditionalFormats.setInitToIsCompletedFavorite(sheet)
ZzzConditionalFormats.setInitToIsCompletedSecondCheck(sheet, category)

if (category === 'directMessage') {
// 「対応済み?」列
ZzzConditionalFormats.setInitToIsCompletedDMResponse(sheet, category)
} else {
// 「ふぁぼ済?」列
ZzzConditionalFormats.setInitToIsCompletedFavorite(sheet, category)
}
},
'「条件付き書式」の設定'
)
}

// 特定条件において行全体を灰色の背景にする「条件付き書式」
export const setGrayBackGroundInSpecificCondition = () => {
const colNameToNumber = ZzzColumnNames.colNameToNumber()
export const setGrayBackGroundInSpecificCondition = (category = '') => {
const colNameToNumber = ZzzColumnNames.colNameToNumber(category)
let columnAlphabet: string
let newRule: GoogleAppsScript.Spreadsheet.ConditionalFormatRule

@@ -200,7 +221,11 @@ namespace createTweetCountingSheets {
)
rules.push(newRule)

columnAlphabet = ZzzConverters.convertColumnNumberToAlphabet(colNameToNumber['ツイ見られない?'])
if (category === 'directMessage') {
columnAlphabet = ZzzConverters.convertColumnNumberToAlphabet(colNameToNumber['DMが見られない?'])
} else {
columnAlphabet = ZzzConverters.convertColumnNumberToAlphabet(colNameToNumber['ツイ見られない?'])
}

newRule = ZzzConditionalFormats.getRuleToSetGrayBackgroundToAllRowCellsInSpecificCondition(
i,
5 changes: 5 additions & 0 deletions lib/tasks/write_db_data_to_sheet.rake
Original file line number Diff line number Diff line change
@@ -23,4 +23,9 @@ namespace :write_db_data_to_sheet do
task sosenkyo_campaigns: :environment do
Sheets::WriteAndUpdate::SosenkyoCampaigns.exec
end

desc '[ダイレクトメッセージ] DBのダイレクトメッセージのデータをシートに書き込む'
task direct_messages: :environment do
Sheets::WriteAndUpdate::DirectMessages.exec
end
end