Skip to content

Commit

Permalink
Merge pull request #237 from true-runes/development
Browse files Browse the repository at this point in the history
v3.3.0
  • Loading branch information
nikukyugamer authored Jul 4, 2022
2 parents cd65099 + f5fb9b0 commit ab11e2f
Show file tree
Hide file tree
Showing 21 changed files with 838 additions and 42 deletions.
48 changes: 48 additions & 0 deletions app/lib/presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,53 @@ def self.normalized_screen_name(screen_name)
screen_name.gsub!(' ', '')
screen_name.gsub('@', '')
end

def self.formatted_product_names_for_tweet(character_name)
products = Character.find_by(name: character_name).products

product_name_long_to_short = {
'幻想水滸伝' => 'I',
'幻想水滸伝II' => 'II',
'幻想水滸外伝Vol.1' => '外1',
'幻想水滸外伝Vol.2' => '外2',
'幻想水滸伝III' => 'III',
'幻想水滸伝IV' => 'IV',
'Rhapsodia' => 'R',
'幻想水滸伝V' => 'V',
'幻想水滸伝ティアクライス' => 'TK',
'幻想水滸伝 紡がれし百年の時' => '紡時'
}

"(#{products.map { |product| product_name_long_to_short[product.name] }.join(',')})"
end
end

class Counting
# { "key1" => 100, "key2" => 99, "key3" => 99, "key4" => 98 } の入力に対し、
# { "key1" => 1, "key2" => 2, "key3" => 2, "key4" => 3 } を返す
# 票数の降順でソートしてあることが前提となるので注意する
def self.key_to_rank_number_by_sosenkyo_style(hash_records)
current_rank = 1
key_to_rank_number = {}
hash_records_keys = hash_records.keys

hash_records_keys.each_with_index do |key, index|
if index == 0
key_to_rank_number[key] = current_rank

next
end

if hash_records[key] == hash_records[hash_records_keys[index - 1]]
key_to_rank_number[key] = key_to_rank_number[hash_records_keys[index - 1]]
else
current_rank += 1

key_to_rank_number[key] = current_rank
end
end

key_to_rank_number
end
end
end
71 changes: 46 additions & 25 deletions app/models/counting_all_character.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ class CountingAllCharacter < ApplicationRecord
scope :invisible, -> { where(is_invisible: true) }
scope :out_of_counting, -> { where(is_out_of_counting: true) }
scope :valid_records, -> { where(is_out_of_counting: false).where(is_invisible: false) }
scope :by_tweet, -> { where(vote_method: :by_tweet) }
scope :by_dm, -> { where(vote_method: :by_direct_message) }

enum vote_method: { by_tweet: 0, by_direct_message: 1, by_others: 99 }
enum vote_method: { by_tweet: 0, by_direct_message: 1, by_others: 99 }, _prefix: true

def self.tweets_whose_invisible_status_is_different_between_sheet_and_database
sheet_invisible_tweet_ids = CountingAllCharacter.invisible.pluck(:tweet_id)
Expand All @@ -24,31 +26,60 @@ def self.tweets_whose_invisible_status_is_different_between_sheet_and_database
result
end

# キャラ1〜3は、AIがsuggestしたものに含まれるか否か?
# キャラ名はキャラデータベースにあるものと一致しているか?
# 同一人物の複数ツイートで複数計上していないか
def self.tweeted_all_characters
chara_1_column_characters = CountingAllCharacter.pluck(:chara_1)
chara_2_column_characters = CountingAllCharacter.pluck(:chara_2)
chara_3_column_characters = CountingAllCharacter.pluck(:chara_3)
def self.all_character_names_including_duplicated
chara_1_column_characters = CountingAllCharacter.valid_records.pluck(:chara_1)
chara_2_column_characters = CountingAllCharacter.valid_records.pluck(:chara_2)
chara_3_column_characters = CountingAllCharacter.valid_records.pluck(:chara_3)

(chara_1_column_characters + chara_2_column_characters + chara_3_column_characters).uniq.compact.sort
# 空文字は削除する
(chara_1_column_characters + chara_2_column_characters + chara_3_column_characters).compact.reject(&:empty?).sort
end

def self.character_db_diff
def self.character_name_to_number_of_votes
all_character_names_including_duplicated.tally.sort_by { |_, v| v }.reverse.to_h
end

def self.character_names_which_not_exist_in_character_db
result = []

tweeted_all_characters.each do |character|
all_character_names_including_duplicated.uniq.each do |character|
result << character if Character.where(name: character).blank?
end

result
end

# もとの行の内容が知りたい
# どうだったらOKでどうだったらNGなのか?
# キャラ計上数が4以上だとNG
# other_tweetがvalid_recordsでないならスルー
# character_names のうちのどれか一つのキャラ名が含まれているかどうか
def includes_either_character_name?(*character_names)
character_names_on_record = [chara_1, chara_2, chara_3].compact.reject(&:empty?)

return false if character_names_on_record.blank?

character_names.any? do |character_name|
character_name.in?(character_names_on_record)
end
end

# character_names の全てのキャラ名が含まれているかどうか
def includes_all_character_names?(*character_names)
character_names_on_record = [chara_1, chara_2, chara_3].compact.reject(&:empty?)

return false if character_names_on_record.blank?

character_names.all? do |character_name|
character_name.in?(character_names_on_record)
end
end

def other_tweets
return if vote_method_by_direct_message?

CountingAllCharacter.includes(:tweet).where(
tweet: { id_number: other_tweet_ids_text.split(',') }
)
end

# FIXME: このメソッドは使用していない
def self.check_other_tweets
result = []

Expand All @@ -64,14 +95,4 @@ def self.check_other_tweets

result
end

def other_tweets
# CountingAllCharacter.where('other_tweet_ids_text like ?', '%|%')
CountingAllCharacter.includes(:tweet).where(
tweet:
{
id_number: other_tweet_ids_text.split(',')
}
)
end
end
45 changes: 45 additions & 0 deletions app/models/counting_bonus_vote.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
class CountingBonusVote < ApplicationRecord
include CountingTools

belongs_to :tweet, optional: true
belongs_to :direct_message, optional: true
belongs_to :user # 鍵でも User のレコードは取得できるので optional 指定は不要

scope :invisible, -> { where(is_invisible: true) }
scope :out_of_counting, -> { where(is_out_of_counting: true) }
scope :valid_records, -> { where(is_out_of_counting: false).where(is_invisible: false) }
scope :by_tweet, -> { where(vote_method: :by_tweet) }
scope :by_dm, -> { where(vote_method: :by_direct_message) }

enum vote_method: { by_tweet: 0, by_direct_message: 1, by_others: 99 }, _prefix: true
enum bonus_category: {
op_cl_illustrations: 0,
short_stories: 1,
result_illustrations: 2,
fav_quotes: 3,
sosenkyo_campaigns: 4
}, _prefix: true

def theme_on_short_story
# TODO: contents に「お題」が含まれている場合は、そのお題を返す
end

def self.all_fav_quote_character_names_including_duplicated
chara_columns = %i[chara_01 chara_02 chara_03 chara_04 chara_05 chara_06 chara_07 chara_08 chara_09 chara_10]
character_names = []

chara_columns.each do |column|
character_names += CountingBonusVote.valid_records.where(bonus_category: :fav_quotes).pluck(column)
end

character_names.compact.reject(&:empty?).sort
end

def self.fav_quote_character_name_to_number_of_votes
all_fav_quote_character_names_including_duplicated.tally.sort_by { |_, v| v }.reverse.to_h
end

def self.fav_quote_ranking_style
Presenter::Counting.key_to_rank_number_by_sosenkyo_style(fav_quote_character_name_to_number_of_votes)
end
end
51 changes: 49 additions & 2 deletions app/models/counting_unite_attack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,54 @@ class CountingUniteAttack < ApplicationRecord

scope :invisible, -> { where(is_invisible: true) }
scope :out_of_counting, -> { where(is_out_of_counting: true) }
scope :valid_records, -> { where(is_out_of_counting: false).where(is_invisible: false) }
scope :no_data, -> { where(product_name: [nil, '']).where(unite_attack_name: [nil, '']) }
scope :valid_records, lambda {
where(is_invisible: false)
.where(is_out_of_counting: false)
.where.not(product_name: [nil, ''])
.where.not(unite_attack_name: [nil, ''])
}
scope :by_tweet, -> { where(vote_method: :by_tweet) }
scope :by_dm, -> { where(vote_method: :by_direct_message) }

enum vote_method: { by_tweet: 0, by_direct_message: 1, by_others: 99 }
enum vote_method: { by_tweet: 0, by_direct_message: 1, by_others: 99 }, _prefix: true

def self.full_ranking
group(:product_name, :unite_attack_name).having('unite_attack_name is not null').order('count_all desc').count
end

def self.product_name_ranking
group(:product_name).having('product_name is not null').order('count_all desc').count
end

# 不正レコードのチェッカ
def self.invalid_records_whose_product_name_is_incorrect
correct_product_names = NaturalLanguage::SuggestUniteAttackNames.title_names

invalid_records = []

valid_records.each do |record|
invalid_records << record unless record.product_name.in?(correct_product_names)
end

invalid_records
end

# 不正レコードのチェッカ
def self.invalid_records_whose_attack_name_is_incorrect
correct_attack_names = OnRawSheetUniteAttack.pluck(:name, :name_en).flatten.reject(&:empty?)

invalid_records = []

valid_records.each do |record|
invalid_records << record unless record.unite_attack_name.in?(correct_attack_names)
end

invalid_records
end

# 'English' というかは 'Not Japanese' であるのだが、便宜上 'English' とする
def self.english_records
includes(:tweet).valid_records.where.not(tweet: { language: 'ja' })
end
end
4 changes: 4 additions & 0 deletions app/models/direct_message.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ def self.missing_records
where(id_number: 1540436647376031755..1540790299618066435)
end

def self.remove_missing_records
where.not(id_number: 1540436647376031755..1540790299618066435)
end

def is_missing_record?
id_number.in?(1540436647376031755..1540790299618066435)
end
Expand Down
10 changes: 10 additions & 0 deletions app/models/on_raw_sheet_result_illustration_totalling.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
class OnRawSheetResultIllustrationTotalling < ApplicationRecord
# on_raw_sheet_result_illustration_totalling
def convert_name_to_gensosenkyo_style(name)
{
"ほげ" => "ほげげげ"
}[name] || name
end
end

# irb(main):003:0> x = { a: 1, b: 2, c: 3 }
# irb(main):004:0> y = { a: 4, c: 5, d: 10 }
# irb(main):007:0> x.merge(y) { |_, oldval, newval| oldval + newval }
# => {:a=>5, :b=>2, :c=>8, :d=>10}
4 changes: 4 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,8 @@ def self.who_vote_two_or_more_without_not_public
def self.did_vote_without_not_public
self.select { |user| user.tweets.gensosenkyo_2021_votes.is_public.count > 0 }
end

def all_counting_records
# TODO: 集計対象となっている全てのレコードを引っ張ってこられる
end
end
48 changes: 42 additions & 6 deletions app/services/sheets/counting/all_characters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ def self.import_via_tweet
rows = SheetData.get_rows(sheet_id: ENV.fetch('COUNTING_ALL_CHARACTERS_SHEET_ID', nil), range: "#{sheet_names[i]}!A2:Q101")

rows.each do |row|
# TODO: 設定ファイルを用いてよりスマートに定義したい
column_vs_value = {
id_on_sheet: row[0],
screen_name: row[1],
tweet_id_number: row[2],
other_tweet_ids_text: row[5],
is_invisible: row[7], # "FALSE" のような文字列なので注意
Expand All @@ -26,8 +26,10 @@ def self.import_via_tweet
next if column_vs_value[:id_on_sheet].blank? || column_vs_value[:tweet_id_number].blank? || column_vs_value[:contents].blank?

tweet = Tweet.find_by(id_number: column_vs_value[:tweet_id_number])
tweet_id = tweet.id
user_id = tweet.user.id
tweet_id = tweet&.id

user = tweet&.user || create_or_find_by_user(column_vs_value)
user_id = user&.id

unique_attrs = {
id_on_sheet: column_vs_value[:id_on_sheet],
Expand All @@ -50,6 +52,8 @@ def self.import_via_tweet

CountingAllCharacter.find_or_initialize_by(unique_attrs).update!(mutable_attrs)
end

puts "#{sheet_name} is Done." # rubocop:disable Rails/Output
end
end

Expand All @@ -68,6 +72,7 @@ def self.import_via_dm
# TODO: 設定ファイルを用いてスマートに定義したい
column_vs_value = {
id_on_sheet: row[0],
screen_name: row[1],
dm_id_number: row[2],
is_invisible: row[5], # "FALSE" のような文字列なので注意
is_out_of_counting: row[6], # "FALSE" のような文字列なので注意
Expand All @@ -88,12 +93,15 @@ def self.import_via_dm

# DMの書式が自由すぎるので、こちらで条件を吸収する
next if column_vs_value[:category] != '①オールキャラ部門' && column_vs_value[:category] != '両部門'

next if column_vs_value[:is_invisible] == 'TRUE' || column_vs_value[:is_out_of_counting] == 'TRUE'
next if column_vs_value[:id_on_sheet].blank? || column_vs_value[:dm_id_number].blank? || column_vs_value[:contents].blank?

dm = DirectMessage.find_by(id_number: column_vs_value[:dm_id_number])
dm_id = dm.id
user_id = dm.user.id
dm_id = dm&.id

# NOTE: dm&.user は不要としてもいい
user = dm&.user || create_or_find_by_user(column_vs_value)
user_id = user&.id

unique_attrs = {
id_on_sheet: column_vs_value[:id_on_sheet],
Expand Down Expand Up @@ -135,6 +143,34 @@ def self.import_via_dm

'[DONE] Sheets::Counting::AllCharacters.import_via_dm'
end

# screen_name でユーザーを一意に特定するのははあまり良くない
def self.create_or_find_by_user(column_vs_value)
existing_user = User.find_by(screen_name: column_vs_value[:screen_name])

if existing_user.blank?
client = TwitterRestApi.client
# ここで API を消費する
user = client.user(column_vs_value[:screen_name])

# NOTE: ユーザーが削除されていると User not found. (Twitter::Error::NotFound) が発生する
# NOTE: その場合はシートのデータを修正する必要がある

new_user = User.new(
id_number: user.id,
name: user.name,
screen_name: user.screen_name,
profile_image_url_https: user.profile_image_url_https.to_s,
is_protected: user.protected?,
born_at: user.created_at
)
new_user.save!

new_user
else
existing_user
end
end
end
end
end
Loading

0 comments on commit ab11e2f

Please sign in to comment.