diff --git a/LineBot/MobServer_gifuroge.rb b/LineBot/MobServer_gifuroge.rb new file mode 100644 index 0000000..62ed038 --- /dev/null +++ b/LineBot/MobServer_gifuroge.rb @@ -0,0 +1,8066 @@ + $:.unshift File.dirname(__FILE__) # ロードパスにカレントディレクトリを追加 +require 'sinatra/base' +require "line/bot" +require "date" +require "rexml/document" +require "json" +require 'nkf' +require 'time' +require "fileutils" +require "rmagick" +require 'open-uri' +require 'uri' +require 'csv' +require '/var/www/lib/aws.rb' +require '/var/www/lib/userpostgres.rb' +require '/var/www/lib/appexeExcelDoc.rb' +require 'httparty' + +#===================================== +# queue用メソッド +#===================================== + +#===================================== +# queue:config +#===================================== + +def set_dbname + return "gifuroge" +end + +def set_commonbase # 画像やスコアボードを保存している場所 + return "/var/www/html/images/gifuRoge" +end + +def set_commonbase2 # 画像やスコアボードを保存している場所をアドレスにしたもの + return "/var/www/html/images/gifuRoge" + #return "https://rogaining.sumasen.net/images/gifuRoge" +end + +def set_originbase # 汎用的な画像を格納している場所。基本的に弄らなくていいはず + return "/var/www/html/images/gifuRoge/asset" + #return "https://rogaining.sumasen.net/images/gifuRoge/asset" +end + +def queue_error_log_base # キューでエラーが出た時にそれを格納するテキストファイルの場所 + return "/home/ubuntu/gifuRogePrintQueError.log" +end + +def s3_key + return "AKIA6LVMTADSVEB5LZ2H" +end + +def s3_Skey + return "KIbm47dqVBxSmeHygrh5ENV1uXzJMc7fLnJOvtUm" +end + +def s3_bucket + return "sumasenrogaining" +end + +def s3_region + return "us-west-2" +end + +def s3_domain + return "https://sumasenrogaining.s3.us-west-2.amazonaws.com" +end + +def get_team_name(zekken_number, event_code) + @pgconn = UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost", "mobilous", 0, dbname) + team_table = UserPostgresTable.new + team_table.useTable(@pgconn, 'team_table') + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + record = team_table.find2(where).first # 期待するのは1レコードだけなので、firstを使って最初のものを取得 + + if record + return record["team_name"] + else + return nil # team_nameが見つからない場合 + end +end + +def get_class_name(zekken_number, event_code) + @pgconn = UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost", "mobilous", 0, dbname) + team_table = UserPostgresTable.new + team_table.useTable(@pgconn, 'team_table') + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + record = team_table.find2(where).first # 期待するのは1レコードだけなので、firstを使って最初のものを取得 + + if record + return record["class_name"] + else + return nil # team_nameが見つからない場合 + end +end + +def get_unique_event_codes(pgconn) + anytable = UserPostgresTable.new + anytable.useTable(pgconn, 'gps_information') + records = anytable.find2(nil, nil, "DISTINCT event_code") + records.map { |row| row["event_code"] } +end + +def get_top_users(pgconn, event_code, class_name) + anytable = UserPostgresTable.new + anytable.useTable(pgconn, 'gps_information') + + # テーブル構造に合わせてクエリを修正 + where_clause = "event_code = '#{event_code}'" + order_clause = "zekken_number ASC, create_at DESC" + + records = anytable.find2(where_clause, order_clause) + + # クラス名でフィルタリング(データベースに class_name カラムがない場合) + filtered_records = records.select { |r| r["class_name"] == class_name } + + # Simulate DISTINCT ON by filtering in Ruby + top_users = filtered_records.group_by { |r| r["zekken_number"] } + .map { |_, user_records| user_records.first } + .first(3) + + top_users.map do |user| + { + "zekken_number" => user["zekken_number"], + "team_name" => user["team_name"], + "class_name" => class_name, + "colabo_company_memo" => user["colabo_company_memo"] + } + end +end + +def get_top_users_by_class(pgconn, event_code) + gps_table = UserPostgresTable.new + gps_table.useTable(pgconn, 'gps_information') + + checkpoint_table = UserPostgresTable.new + checkpoint_table.useTable(pgconn, 'checkpoint_table') + + team_table = UserPostgresTable.new + team_table.useTable(pgconn, 'team_table') + + gps_records = gps_table.find2("event_code = '#{event_code}' AND colabo_company_memo = 'FC岐阜'") + checkpoint_records = checkpoint_table.find2("event_code = '#{event_code}'") + team_records = team_table.find2("event_code = '#{event_code}'") + + checkpoint_data = checkpoint_records.group_by { |r| r["cp_number"] } + team_data = team_records.group_by { |r| r["zekken_number"] } + + user_data = gps_records.group_by { |r| r["zekken_number"] }.map do |zekken_number, records| + team_info = team_data[zekken_number]&.first || {} + + daily_scores = calculate_daily_scores(records, checkpoint_data) + best_score = daily_scores.max_by { |_, score| score[:point] } + + { + "zekken_number" => zekken_number, + "event_code" => event_code, + "team_name" => team_info["team_name"], + "class_name" => team_info["class_name"], + "best_score" => best_score[1][:point], + "best_cp_count" => best_score[1][:cp_count], + "best_late_point" => best_score[1][:late_point], + "best_overtime_penalty" => best_score[1][:overtime_penalty], + "best_duration_minutes" => best_score[1][:duration_minutes], + "last_checkin" => best_score[1][:end_time], + "daily_scores" => daily_scores.transform_keys { |k| k.to_s } + } + end + + user_data.group_by { |u| u["class_name"] }.transform_values do |users| + users.sort_by { |u| [-u["best_score"], -u["best_cp_count"]] }.first(3) + end +end + +def get_all_users_by_class(pgconn, event_code) + gps_table = UserPostgresTable.new + gps_table.useTable(pgconn, 'gps_information') + + checkpoint_table = UserPostgresTable.new + checkpoint_table.useTable(pgconn, 'checkpoint_table') + + team_table = UserPostgresTable.new + team_table.useTable(pgconn, 'team_table') + + gps_records = gps_table.find2("event_code = '#{event_code}' AND colabo_company_memo = 'FC岐阜'") + checkpoint_records = checkpoint_table.find2("event_code = '#{event_code}'") + team_records = team_table.find2("event_code = '#{event_code}'") + + checkpoint_data = checkpoint_records.group_by { |r| r["cp_number"] } + team_data = team_records.group_by { |r| r["zekken_number"] } + + user_data = gps_records.group_by { |r| r["zekken_number"] }.map do |zekken_number, records| + team_info = team_data[zekken_number]&.first || {} + + daily_scores = calculate_daily_scores(records, checkpoint_data) + best_score = daily_scores.max_by { |_, score| score[:point] } + + { + "zekken_number" => zekken_number, + "event_code" => event_code, + "team_name" => team_info["team_name"], + "class_name" => team_info["class_name"], + "best_score" => best_score[1][:point], + "best_cp_count" => best_score[1][:cp_count], + "best_late_point" => best_score[1][:late_point], + "best_overtime_penalty" => best_score[1][:overtime_penalty], + "best_duration_minutes" => best_score[1][:duration_minutes], + "last_checkin" => best_score[1][:end_time], + "daily_scores" => daily_scores.transform_keys { |k| k.to_s } + } + end + + user_data.group_by { |u| u["class_name"] }.transform_values do |users| + users.sort_by { |u| [-u["best_score"], -u["best_cp_count"]] } + end +end + +def calculate_daily_scores(records, checkpoint_data) + records.group_by { |r| Date.parse(r["create_at"]) }.transform_values do |day_records| + photo_point = 0 + buy_point = 0 + late_point = 0 + cp_count = 0 + + # 開始時間と終了時間を特定 + start_time = Time.parse(day_records.min_by { |r| r["create_at"] }["create_at"]) + end_time = Time.parse(day_records.max_by { |r| r["create_at"] }["create_at"]) + + day_records.each do |r| + cp_info = checkpoint_data[r["cp_number"]]&.first || {} + + if r["cp_number"].to_i > 0 + cp_count += 1 + + if !r["buy_flag"] && !r["minus_photo_flag"] + photo_point += cp_info["photo_point"].to_i + end + + if r["buy_flag"] + buy_point += cp_info["buy_point"].to_i + end + end + + late_point += r["late_point"].to_i + end + + # 超過時間のペナルティ計算 + duration_seconds = (end_time - start_time).to_i + overtime_seconds = [duration_seconds - 18000, 0].max # 5時間 = 18000秒 + + overtime_penalty = if overtime_seconds > 0 + base_penalty = 50 # 1秒でも超えたら50点引く + additional_penalty = (overtime_seconds / 60.0).floor * 50 # 1分ごとに追加で50点引く + base_penalty + additional_penalty + else + 0 + end + + point = photo_point + buy_point - late_point - overtime_penalty + + { + point: point, + cp_count: cp_count, + late_point: late_point, + overtime_penalty: overtime_penalty, + start_time: start_time.strftime("%Y-%m-%d %H:%M:%S"), + end_time: end_time.strftime("%Y-%m-%d %H:%M:%S"), + duration_minutes: (duration_seconds / 60.0).ceil + } + end +end + +# get_top_users_by_class メソッドは変更なし + +def calculate_points(records, checkpoint_data) + photo_point = 0 + buy_point = 0 + late_point = 0 + cp_count = 0 + + records.each do |r| + cp_info = checkpoint_data[r["cp_number"]]&.first || {} + + if r["cp_number"].to_i > 0 + cp_count += 1 + + if !r["buy_flag"] && !r["minus_photo_flag"] + photo_point += cp_info["photo_point"].to_i + end + + if r["buy_flag"] + buy_point += cp_info["buy_point"].to_i + end + end + + late_point += r["late_point"].to_i + end + + point = photo_point + buy_point - late_point + + [point, cp_count, late_point] +end + +def calculate_user_scores(pgconn, zekken_number, event_code) + gps_table = UserPostgresTable.new + gps_table.useTable(pgconn, 'gps_information') + + today = Date.today + start_date = Date.new(today.year, today.month, 1) + end_date = Date.new(today.year, today.month, -1) # 月末日 + + where_clause = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}' " \ + "AND create_at >= '#{start_date}' AND create_at <= '#{end_date}' " \ + "AND colabo_company_memo = 'FC岐阜'" + + records = gps_table.find2(where_clause) + + total_score = records.count { |r| r["cp_number"].to_i > 0 } + last_checkin = records.map { |r| r["create_at"] }.max + + { + "best_score" => total_score, + "total_score" => total_score, + "last_checkin" => last_checkin + } +end + +##移動経路画像作成 + +# 1. 上位ユーザーの移動データを取得する関数 +def get_top_users_routes(pgconn, event_code, class_name, limit = 3) + anytable = UserPostgresTable.new + anytable.useTable(pgconn, 'gps_information') + + top_users = get_top_users(pgconn, event_code, class_name) + + routes = {} + top_users.each do |user| + zekken_number = user["zekken_number"] + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}' ORDER BY create_at ASC" + route = anytable.find2(where) + routes[zekken_number] = route.map do |point| + { + latitude: point['latitude'].to_f, + longitude: point['longitude'].to_f, + timestamp: point['create_at'] + } + end + end + + routes +end + +# 2. 移動経路を描画する関数 +def draw_route(image, route, color) + draw = Magick::Draw.new + draw.stroke(color) + draw.stroke_width(2) + + points = route.map do |point| + [point['longitude'].to_f, point['latitude'].to_f] + end + + draw.polyline(*points.flatten) + draw.draw(image) +end + +# 3. 画像生成と保存を行う関数 +def generate_route_image(routes, event_code) + width = 800 + height = 600 + image = Magick::Image.new(width, height) { self.background_color = 'white' } + + # ルートの座標を正規化するための関数 + normalize = lambda do |val, min, max| + (val - min) / (max - min) + end + + # すべてのルートの座標範囲を取得 + all_points = routes.values.flatten + min_lat = all_points.map { |p| p['latitude'].to_f }.min + max_lat = all_points.map { |p| p['latitude'].to_f }.max + min_lon = all_points.map { |p| p['longitude'].to_f }.min + max_lon = all_points.map { |p| p['longitude'].to_f }.max + + colors = ['red', 'blue', 'green'] + routes.each_with_index do |(zekken_number, route), index| + normalized_route = route.map do |point| + x = normalize.call(point['longitude'].to_f, min_lon, max_lon) * width + y = height - normalize.call(point['latitude'].to_f, min_lat, max_lat) * height + [x, y] + end + + draw_route(image, normalized_route, colors[index]) + end + + filename = "top_routes_#{event_code}_#{Time.now.strftime('%Y%m%d%H%M%S')}.png" + image.write(filename) + filename +end + + + +#===================================== +# queue:util +#===================================== + +def to_boolean str + str.to_s.downcase == "true" +end + +#===================================== +# queue:DB +#===================================== + +# SELECT + +def getFinalReport zekken_number, event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'report_list' ) + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + + list = anytable.find2(where) + result = "" + + list.each { |rec| + result = rec["report_address"] + } + + @pgconn.disconnect + + if result == "" || result == nil then + return "no report" + end + + return result + +end + +def getGpsInfo zekken_number, event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'gps_information' ) + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}' ORDER BY serial_number" + p "where : #{where}" + list = anytable.find2(where) + result = [] + p "list : #{list}" + if list == nil then + @pgconn.disconnect + return [] + end + + count = 0 + + list.each { |rec| + result[count] = {"cp_number" => rec['cp_number']} + count += 1 + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return [] + end +end + +def getPhotoFromRR zekken_number, event_code, num #RR => RouteResult + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + if num <= 60 + table = 'route_result' + else + table = 'route_result_2' + end + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,table ) + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + + list = anytable.find2(where) + result = {} + + if list == nil then + return {"result" => "ERROR"} + end + + docpath = set_commonbase() + '/' + event_code + '/' + zekken_number + + if( !Dir.exist?(docpath) )then + if( Dir.mkdir( docpath,0755 ) == 0 ) then + end + end + + list.each { |rec| + for i in 1..num do + begin + if rec["cp#{i}_ph"].include?(s3_domain()) then + extension = result["cp#{i}_ph"].to_s.split('.').last + result["cp#{i}_ph"] = rec["cp#{i}_ph"].gsub(s3_domain(),set_commonbase()).gsub(".#{extension}","_th.#{extension}") + elsif rec["cp#{i}_ph"].include?(set_commonbase2()) then + result["cp#{i}_ph"] = rec["cp#{i}_ph"].gsub(set_commonbase2(),set_commonbase()) + else + result["cp#{i}_ph"] = "#{set_commonbase()}/asset/photo_none.png" + end + rescue => e + p "error : #{e}, result[cp#{i}_ph] :#{result["cp#{i}_ph"]}" + result["cp#{i}_ph"] = "#{set_commonbase()}/asset/photo_none.png" + end + if result["cp#{i}_ph"].include?("asset/asset") then + result["cp#{i}_ph"].gsub!('asset/asset', 'asset') + end + if File.exist?(result["cp#{i}_ph"]) == false then + begin + filename = rec["cp#{i}_ph"].split('/').last + fullpath = docpath + '/' + filename + fullpath2 = s3_domain + '/' + URI.encode_www_form_component(event_code, enc=nil) + '/' + zekken_number + '/' + filename + URI.open(fullpath2) do |image| + File.open(fullpath, 'w') do |file| + file.write(image.read) + end + end + extension = filename.split('.').last + + filenameTh = filename.gsub(".#{extension}","_th.#{extension}") + + imageOri = Magick::Image.read(fullpath).first + imageTh = imageOri.scale(image_size_width(), image_size_height()) + imageTh.write("temp/#{filenameTh}") + + nextpath = docpath + '/' + filenameTh + + FileUtils.mv("/var/www/temp/#{filenameTh}",nextpath) + # File.delete(fullpath) + + result["cp#{i}_ph"] = nextpath + rescue => e + p "error : #{e}, rec[cp#{i}_ph] :#{rec["cp#{i}_ph"]}" + result["cp#{i}_ph"] = "#{set_commonbase()}/asset/photo_none.png" + end + end + + begin + result["cp#{i}_p"] = rec["cp#{i}_p"] + rescue => e + p "error : #{e}, result[cp#{i}_p] : #{result["cp#{i}_p"]}" + end + + begin + result["cp#{i}_s"] = rec["cp#{i}_s"].gsub(set_commonbase2(),set_commonbase()) + rescue => e + p "error : #{e}, result[cp#{i}_s] : #{result["cp#{i}_s"]}" + result["cp#{i}_s"] = "#{set_commonbase()}/asset/photo_none.png" + end + if result["cp#{i}_s"].include?("asset/asset") then + result["cp#{i}_s"].gsub!('asset/asset', 'asset') + end + if File.exist?(result["cp#{i}_s"]) == false then + result["cp#{i}_s"] = "#{set_commonbase()}/asset/photo_none.png" + end + end + } + + @pgconn.disconnect + + if result == [] || result == nil then + return {"result" => "ERROR"} + end + + result["result"] = "OK" + + return result +end + +def getPrintQueueMemory + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'print_queue_memory' ) + + where = "0 = 0" + + list = anytable.find2(where) + result = [] + + list.each { |rec| + result.push(rec) + } + + @pgconn.disconnect + + return result + +end + +# INSERT + +def inputFinalReport zekken_number, event_code, pdf_address + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'report_list' ) + + title = ["zekken_number", "event_code", "report_address"] + record = {"zekken_number" => zekken_number, "event_code" => event_code, "report_address" => pdf_address} + + sql = anytable.makeInsertKeySet(title,record) + begin + ret = anytable.exec(sql) # true or false + rescue => error + p error + end + + @pgconn.disconnect + + return "200 OK" +end + +# UPDATE + +def changeFinalReport zekken_number, event_code, pdf_address + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + rec = {"report_address" => pdf_address} + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + + begin + @pgconn.update("report_list",rec,where) + rescue => e + p e + + @pgconn.disconnect + + return "UPDATE ERROR" + end + + @pgconn.disconnect + + return "OK" + +end + +def removeQueueMemory + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'print_queue_memory' ) + + where = "serial_number = (SELECT min(serial_number) FROM print_queue_memory)" + + begin + p anytable.remove(where) + + @pgconn.disconnect + + return "200 OK" + rescue => e + p e + @pgconn.disconnect + return "delete error" + end + +end + +#===================================== +# queue:s3 +#===================================== + +def s3Uploader data_dir, filepath, filename + + bucket = s3_bucket().freeze + region = s3_region().freeze + access_key = s3_key().freeze + secret_key = s3_Skey().freeze + + aws_storage = S3_StorageUtil.new( access_key,secret_key,region,bucket,data_dir ) + aws_bucket = S3_FolderUtil.new( "offlineRecog/work",aws_storage ) + + originPath = filepath + destPath = data_dir + filename = filename + + aws_bucket.uploadFile( originPath,destPath,filename ) + + aws_url = s3_domain() + '/' + data_dir + '/' + filename + + return aws_url + +end + +#===================================== +# queue:scoreboard +#===================================== + +def makeScoreboard zekken_number, event_code, reprintF = false, budleF = false + p "makeScoreboard" + filepath = getScoreboardGeneral(zekken_number, event_code) + p "return filepath" + if filepath == "no_data" then + p "no data error" + return "no data error" + end + + if reprintF then + date_memory = DateTime.now.to_s.gsub(':','-').gsub('+','_') + nextpath = set_commonbase() + "/#{event_code}" + "/scoreboard/#{zekken_number}_scoreboard_" + date_memory + ".xlsx" + else + nextpath = set_commonbase() + "/#{event_code}" + "/scoreboard/#{zekken_number}_scoreboard.xlsx" + end + p "nextpath set" + if( !Dir.exist?(set_commonbase() + "/#{event_code}" + "/scoreboard") )then + if( Dir.mkdir( set_commonbase() + "/#{event_code}" + "/scoreboard",0755 ) == 0 ) then + #p "mkdir #{commonbase}" + end + end + p "dir set" + puts "filepath=#{filepath},nextpath=#{nextpath}" + FileUtils.mv(filepath,nextpath) + p "file move" + docpath_user = set_commonbase() + "/#{event_code}" + "/scoreboard" + pdffile = "#{zekken_number}_scoreboard" + + puts "PDF file will be #{pdffile}_#{date_memory} ..." + if reprintF then + pdffile = pdffile + '_' + date_memory + end + p "bofore PDF" + command ="/home/mobilousInstance/jodconverter-cli-4.4.5-SNAPSHOT/bin/jodconverter-cli -o #{docpath_user}/#{pdffile}.xlsx #{docpath_user}/#{pdffile}.pdf" #郡上のイベント後はこちらの仕様に置き換える + system( command ) + puts command + #system("echo 'sumasen@123' |sudo -S /var/www/lib/generatePDF.sh #{docpath_user} #{pdffile}") + p "after PDF" + aws_url = s3Uploader("#{event_code}/scoreboard", docpath_user, pdffile + '.pdf') + p "s3 upload complete" + if getFinalReport(zekken_number, event_code) == "no report" then + inputFinalReport(zekken_number, event_code, aws_url) + else + changeFinalReport(zekken_number, event_code, aws_url) + end + p "report complete" + # File.delete(nextpath) + if budleF == false then + # File.delete(nextpath.gsub('.xlsx','.pdf')) + return nextpath.gsub('.xlsx','.pdf') + end +end + +def getScoreboardGeneral zekken_number, event_code + p "getScoreboardGeneral" + #usernameエラーで引っかかる + # + #$bean.read_bean + #username = $bean.username + username = 'test' + record = {} + + record["zekken_number"] = zekken_number + p "zekken_number : #{zekken_number}, event_code : #{event_code}" + result = getGpsInfo(zekken_number, event_code) + + if result == [] then + p "getGPSInfo no_data" + return "no_data" + end + + count = 0 + + result.each { |rec| + count += 1 + } + + result2 = getPhotoFromRR(zekken_number, event_code, count) + + if result2 == {} || result2["result"] == "ERROR" then + p "getPhotoFromRP no_data" + return "no_data" + + end + + record.merge!(result2) + + if count <= 60 then + document = "scoreboardGeneral" + else + document = "scoreboardGeneral2" + end + + count = count * 2 + 1 + + record["num_image"] = count + #return record.to_s #昼休み後ここから + ExcelObject.resetClass + + doc = AppExeExcelDoc.new + #doc = AppExeGeneralDocument.new + doc.init( username,0,document,"jp","/var/www/docbase","/home/mobilousInstance" ) # <== "/home/mobilousInstance" を出力先のベースフォルダーにしてください。 + + pgconn=UserPostgres.new + dbname = set_dbname() + pgconn.connectPg("localhost","mobilous",0,dbname) + + rec = JSON.parse( JSON.generate(record) ) + #return rec + #@sheetname = sheet + #filename = doc.makeReport( pgconn,rec,"outfile.xlsx",0 ) # ==> Use ini file defnition 2021-11-15 + doc.makeReport( pgconn,rec ) + + # make a excel file under /var/www/docbase/(@username)/(@projectno)/ + + #file_path = filename.to_s.gsub(/wrote excel file on /,"") + #puts "=========> file_path = #{file_path}" + pgconn.disconnect + filename = doc.outfile + file_path = doc.outpath + puts "=========> file_path = #{file_path}, filename = #{filename}" + + return file_path + +end + +#==================================== +# キューイング処理本体 +#==================================== + +$queue = Queue.new + +Thread.new do + loop do + begin + item = JSON.parse($queue.pop) + p "queue pop : #{item}" + makeScoreboard(item["zekken_number"],item["event_code"],to_boolean(item["reprintF"]),false) + result = removeQueueMemory() + if result == "delete error" then + timestamp = Time.now.strftime("%Y-%m-%d %H:%M:%S") + item_value = defined?(item) ? item.to_s : "" + error_message = "#{timestamp}=> #{item_value} : queue memory delete fail\n" + File.open(queue_error_log_base(), "a") do |file| + file.write(error_message) + end + end + rescue => e + timestamp = Time.now.strftime("%Y-%m-%d %H:%M:%S") + item_value = defined?(item) ? item.to_s : "" + error_message = "#{timestamp}=> #{item_value} : #{e.message}\n" + File.open(queue_error_log_base(), "a") do |file| + file.write(error_message) + end + end + end +end + +data = getPrintQueueMemory() +p "data : #{data}" +data.each { |rec| + json = JSON.parse(rec["queue_detail"]) + + jhash = {"zekken_number" => json["zekken_number"], "event_code" => json["event_code"], "reprintF" => json["reprintF"]} + + new_json = JSON.generate(jhash) + + p "queue add : #{new_json}" + + $queue << new_json +} + +#==================================== +# sinatraここから +#==================================== + +module Sinatra + module MobServer_gifuroge + module Helpers + + + +#==================================== +# utils +#==================================== + + def crossdomain + headers 'Access-Control-Allow-Origin' => '*' + end + + def headjson + headers 'Content-Type' => 'application/json; charset=utf-8' + end + +#==================================== +# config +#==================================== + + def client + # p "boot client method!" + @client ||= Line::Bot::Client.new { |config| + config.channel_id = "1657548864" + config.channel_secret = "01846a8d9d1832e55626098fca072e05" + config.channel_token = "MGv4aes9X9aTDBBv7ocR8jgine8ct7f4XpLreUt6qg8/WuEhTWhNJTa1vlbJIVOxvWTGR4SBpECM8SkccZCGF4rfrQxsATf20AK5/QNZlXZ6rh8J1R3Sth8yaX1mMNIa1ZJMvw2whdVSe90ZdywZsgdB04t89/1O/w1cDnyilFU=" + } + end + + def set_dbname + return "gifuroge" + end + + def set_commonbase # 画像やスコアボードを保存している場所 + return "/var/www/html/images/gifuRoge" + end + + def set_commonbase2 # 画像やスコアボードを保存している場所をアドレスにしたもの + return "https://rogaining.sumasen.net/images/gifuRoge" + end + + def set_originbase # 汎用的な画像を格納している場所。基本的に弄らなくていいはず + return "https://rogaining.sumasen.net/images/gifuRoge/asset" + end + + def set_rogSimBase #ロゲイニングシミュレーターの位置 + return "/home/mobilousInstance/rogaining/rogaining" + end + + def location_threshold # 位置情報の閾値 + return 30 + end + + def special_threshold + return 100 + end + + def latitude_1m # 1mあたりの緯度 + return 0.000008983148616 + end + + def longitude_1m # 1mあたりの経度 + return 0.000010966382364 + end + + def image_size_width + return 150 + end + + def image_size_height + return 105 + end + + def s3_key + return "AKIA6LVMTADSVEB5LZ2H" + end + + def s3_Skey + return "KIbm47dqVBxSmeHygrh5ENV1uXzJMc7fLnJOvtUm" + end + + def s3_bucket + return "sumasenrogaining" + end + + def s3_region + return "us-west-2" + end + + def s3_domain + return "https://sumasenrogaining.s3.us-west-2.amazonaws.com" + end + + def latitude_threshols mode = nil + if mode == "special" + return special_threshold() * latitude_1m() + end + return location_threshold() * latitude_1m() + end + + def longitude_threshols mode = nil + if mode == "special" + return special_threshold() * longitude_1m() + end + return location_threshold() * longitude_1m() + end + +#==================================== +# text +#==================================== + + def text_importantError errorCode + return "エラーコード:#{errorCode}\nゼッケン番号とエラーコードを添えて、運営に問い合わせて下さい。" + end + + # エラーコード一覧 + # STA-001 : パスワード入力のキャンセルに失敗した状態。応急対応:運営側で当該ユーザーIDのchat_statusレコードを削除。 + # STA-002 : 処理には成功したがchat_statusのレコードデリートに失敗した状態。応急対応:処理には成功していることを伝えた上で、運営側で当該ユーザーIDのchat_statusレコードを削除。 + # STA-003 : 写真受付のキャンセルに失敗した状態。応急対応:運営側で当該ユーザーのchat_statusレコードを削除 + # USR-001 : LINEのユーザー名を取得できていない状態。応急対応:エラーを無視してゼッケン番号を登録してもらう。ゼッケン番号とユーザーIDの紐付けが出来たら、手動でユーザー名をuser_tableに追加する。 + # USR-002 : ログインに成功したが、user_tableのレコードアップデートに失敗した状態。応急対応:ログを確認し、実際にログインに成功しているか検証した上で、手動でゼッケン番号とチーム名をuser_tableに追加する。 + # USR-003 : ログアウトの処理に失敗した。応急対応:LINEのアカウント名を聞き取り、手動でuser_tableからteam_nameとzekken_nameの中身を消去する。 + # DBS-001 : そのユーザーが何時間部門のユーザーなのかを認識できなくなった状態。データベースに何かしらの問題が生じていることが考えられるため、竜一に連絡 + + def text_zekkenRegister zekken_number + return "#{zekken_number}の代表登録を受け付けました。\n確認のためパスワードを入力し、送信して下さい。" + end + + def text_teamRegister user_name, team_name + return "#{user_name}さんをチーム:#{team_name}の代表として登録しました。" + end + + def text_noZekken1 user_name + return "#{user_name}さんは現在チームの代表として登録されていません。\nあなたがチームの代表であるなら、" + end + + def text_noZekken2 + return "ゼッケン番号:[ゼッケン番号]" + end + + def text_noZekken3 + return "の形でゼッケン番号を登録して下さい。" + end + + def text_noZekkenNumber + return "入力されたゼッケン番号は存在しません。タイプミスがないか確認し、再度送信して下さい。" + end + + def text_alreadyZekken + return "ログインに成功しましたが、入力されたゼッケン番号のチームは既に代表が登録されています。\nあなたが代表で他の方が代表登録してしまっている場合、その方に「ログアウト」と入力して貰ってから再度パスワードを入力して下さい。\n他の誰かが代表登録しているわけでもないのにこのエラーが出る場合、不正ログインが疑われますので、運営に問い合わせて下さい。" + end + + def text_passwordError + return "パスワードが一致しません。もう一度入力して下さい。\nゼッケン番号の入力からやり直す場合は「キャンセル」と入力して下さい。" + end + + def text_AuthorizationCancel + return "受付をキャンセルしました。" + end + + def text_loguotSuccess + return "ログアウトの処理が完了しました。" + end + + def text_errorCPnumber + return "CP番号は自然数で入力してください。" + end + + def text_errorNoCP cp_number + return "CP番号:#{cp_number}に該当するチェックポイントがありません。もう一度ご確認ください。" + end + + def text_getCPnumber cp_number, cp_name + return "CP番号:#{cp_number}は#{cp_name}です。よろしいですか?\n宜しければ、続けて写真を送って下さい。\n間違っていれば「NO」と返信して下さい。" + end + + def text_noLocation + return "位置情報の周辺15mにチェックポイントを発見できませんでした。" + end + + def text_noLocationCSB cp_number, cp_name + return "位置情報の周辺15mに#{cp_number}:#{cp_name}を発見できませんでした。\nチェックポイントの指定をやり直す場合は「キャンセル」と返信して下さい。" + end + + def text_registredCP cp_number, cp_name + return "#{cp_number}:#{cp_name}は既に登録されています。" + end + + def text_registreCP cp_number, cp_name + return "#{cp_number}:#{cp_name}を登録しました。" + end + + def text_standByBuyPoint cp_number, cp_name + return "#{cp_number}:#{cp_name}はサービスポイントのチェックポイントです。\nチェックポイントで撮影した写真をアップロードして下さい。特定の対象を写真に含めると加点対象になります。\n想定と異なるチェックポイントが認識されてしまった場合は「キャンセル」で写真受付をキャンセル出来ます。" + end + + def text_BuyPointError cp_number, cp_name + return "#{cp_number}:#{cp_name}はサービスポイントのチェックポイントなので位置情報では認証できません。\n写真をアップロードして下さい。" + end + + def text_getGPSlogger + return "GPSloggerのデータを受け取りました。結果発表をお待ち下さい。" + end + + def text_approval_cp cp_name + return "チェックポイント:#{cp_name}の写真が承認されました。" + end + + def text_not_approval_cp cp_name, reason + return "チェックポイント:#{cp_name}の写真が承認されませんでした。\n事由:#{reason}\nお手数ですが、CPの宣言からやり直して下さい。" + end + + def text_goalCheck1 + return "ゴールチェックポイントを確認しましたが、ゴールは" + end + + def text_goalCheck2 + return "ゴール:[ゴールした時刻]" + end + + def text_goalCheck3 + return "と入力して下さい。" + end + + def text_getGoal goal_time + return "#{goal_time}でゴールタイムを記録しました。続けてタイマーの写真を送って下さい。\nゴールタイムの入力ミスなどがあった場合には「キャンセル」で、写真受付をキャンセルして、再度ゴールタイムを登録して下さい。" + end + + def text_getGoalPhoto + return "ゴールの写真を記録しました。お疲れ様でした。\n印刷受付にレポートを受け取りに来て下さい。" + end + + def text_alreadyGoal + return "既にゴールタイムの記録は完了しております。結果発表をお待ち下さい。" + end + + def text_goalError + return "ゴールタイムの認識に失敗しました。「○○:○○」若しくは「○○時○○分」で入力して下さい。\n正しく入力しているのにこのエラーが出ている場合は運営に問い合わせて下さい。" + end + + def text_notAgent + return "パスワードが一致する代理人が存在しません。" + end + + def text_agentStart event_name + return "イベント:#{event_name}の代理人としてログインしました。" + end + + def text_ask_for_receipt_image cp_number + return "写真を登録しました。cp: #{cp_number}は対象の商品を購入したレシートの画像を送っていただくとさらにポイントが追加されます。\nレシート写真を送ってください。\n「キャンセル」でレシート写真受付をキャンセル出来ます。" + end + + def text_insertComplete cp_number, cp_name, insert_number + return "#{cp_number}:#{cp_name}を#{insert_number}に挿入しました。" + end + + def text_noCPregist cp_number + return "このチームの通過記録に#{cp_number}を通過したという記録はありません。" + end + + def text_deleteCP sn + return "通し番号:#{sn}を削除しました。" + end + + def text_moveCP sn, new_sn + return "通し番号:#{sn}の記録を通し番号:#{new_sn}に移動しました。" + end + + def text_moveSameNum + return "移動元と移動先に同じ通し番号が入力されています。" + end + + def text_moveOverNum + return "存在しない通し番号が指定されています。" + end + + def text_goalUpdate goal_time + return "ゴール時間を#{goal_time}に更新し、遅刻点も再計算しました。" + end + + def text_reprint + return "新しいレポートの生成を開始しました。" + end + + def text_argumentError_Insert + return "INSERTの引数が正しくありません。\nINSERT [挿入したい通し番号] [挿入したいチェックポイント番号]\nの書式で入力して下さい。" + end + + def text_notNaturakNumber + return "挿入する番号は自然数で入力して下さい。" + end + + def text_startStand + return "「スタート」を実行するとチェックポイント通過情報が初期化されます。\n問題なければ「YES」、中断する場合は「NO」と入力して下さい。" + end + + def text_startRun + return "チェックポイント通過情報を初期化し、ロゲイニングを開始する準備が整いました。" + end + + def text_noEventName + return "該当するイベントコードが見つかりませんでした。" + end + + def text_zekkenNotExist zekken_number + return "#{zekken_number}に該当するチームがありませんでした。" + end + + def text_agentLogin team_name + return "#{team_name}に代理ログインしました。" + end + + def text_agentLogout + return "代理ログアウトしました。" + end + +#==================================== +# DB:SELECT (get) +#==================================== + + def getUserName userId + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'user_table' ) + + where = "userid = '" + userId.to_s + "'" + + list = anytable.find2(where) + result = {} + + if list == nil then + return getNewUserName(userId) + end + + list.each { |rec| + result = rec + } + + @pgconn.disconnect + + if result != {} && result != nil then + return result + else + return getNewUserName(userId) + end + end + + def getUserIdByZekkenNumber zekken_number, event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'user_table' ) + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + + list = anytable.find2(where) + result = "" + + if list == nil then + return "no zekken number" + end + + list.each { |rec| + result = rec["userid"] + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return "no zekken number" + end + end + + def getZekkenNumberByUserId userId + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'user_table' ) + + where = "userid = '#{userId}'" + + list = anytable.find2(where) + result = "" + + if list == nil then + return "no zekken number" + end + + list.each { |rec| + result = rec["zekken_number"] + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return "no zekken number" + end + end + + + def getCPname cp_number, event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'checkpoint_table' ) + + where = "cp_number = " + cp_number.to_s + " AND event_code = '#{event_code}'" + + list = anytable.find2(where) + result = "" + + if list == nil then + return "no cp error" + end + + list.each { |rec| + result = rec["cp_name"] + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return "no cp error" + end + end + + def getMaxNumByGI zekken_number, event_code # GI => gps_information + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'gps_information' ) + + where = "serial_number = (SELECT max(serial_number) FROM gps_information WHERE zekken_number = '#{zekken_number}' AND event_code = '#{event_code}' )" + + list = anytable.find2(where) + result = "" + + if list == nil then + return 0 + end + + list.each { |rec| + result = rec['serial_number'] + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return 0 + end + + end + + def getZekkenListByUT #UT => user_table + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'user_table' ) + + list = anytable.find2("zekken_number IS NOT NULL") + result = [] + + if list == nil then + return [] + end + + list.each { |rec| + result.push(rec['zekken_number']) + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return [] + end + end + + def getZekkenListByTT event_code #TT => team_table + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'team_table' ) + + list = anytable.find2("class_name != 'test' AND event_code = '#{event_code}'") + result = [] + + if list == nil then + return [] + end + + list.each { |rec| + result.push(rec['zekken_number']) + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return [] + end + end + + def getPhotoList zekken, event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'gps_information' ) + + where = "zekken_number = '#{zekken}' AND event_code = '#{event_code}'" + + list = anytable.find2(where) + result = [] + + if list == nil then + return [] + end + + list.each { |rec| + if rec['image_address'] != "#{set_originbase}/location_checked.png" && rec['image_address'] != "#{set_originbase}/location_checked.png" && rec['image_address'] != "#{set_originbase}/photo_none.png" && rec['image_address'] != "#{set_originbase}/asset/photo_none.png" && rec['image_address'] != "#{set_originbase}/start.png" && rec['image_address'] != "#{set_originbase}/asset/start.png" then + result.push(rec['image_address']) + end + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return [] + end + end + + def getGpsInfo zekken_number, event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'gps_information' ) + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}' ORDER BY serial_number" + + list = anytable.find2(where) + result = [] + + if list == nil then + return [] + end + + count = 0 + + list.each { |rec| + result[count] = {"cp_number" => rec['cp_number']} + count += 1 + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return [] + end + end + + def getCPnameByThreshols latitude, longitude, event_code, cp_number = nil + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'checkpoint_table' ) + + if cp_number.to_i == 999 then + where = "latitude BETWEEN #{latitude - latitude_threshols("special")} AND #{latitude + latitude_threshols("special")} AND longitude BETWEEN #{longitude - longitude_threshols("special")} AND #{longitude + longitude_threshols("special")} AND event_code = '#{event_code}'" + else + where = "latitude BETWEEN #{latitude - latitude_threshols()} AND #{latitude + latitude_threshols()} AND longitude BETWEEN #{longitude - longitude_threshols()} AND #{longitude + longitude_threshols()} AND event_code = '#{event_code}'" + end + + if cp_number != nil + where = where + " AND cp_number = #{cp_number}" + end + + p "where : #{where}" + + list = anytable.find2(where) + result = {} + + if list == nil then + result["result"] = "no cp error" + return result + end + + list.each { |rec| + result["cp_number"] = rec["cp_number"] + result["cp_name"] = rec["cp_name"] + result["buy_point"] = rec["buy_point"] + } + + @pgconn.disconnect + + if result != {} && result != nil then + result["result"] = "OK" + return result + else + result["result"] = "no cp error" + return result + end + end + + def getTeamDataByZekken_number zekken_number, event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'team_table' ) + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + + list = anytable.find2(where) + result = {} + + if list == nil then + result["result"] = "ERROR" + @pgconn.disconnect + return result + end + + list.each { |rec| + result["zekken_number"] = rec["zekken_number"] + result["team_name"] = rec["team_name"] + result["class_name"] = rec["class_name"] + } + + @pgconn.disconnect + + if result != {} && result != nil then + result["result"] = "OK" + return result + else + result["result"] = "ERROR" + return result + end + end + + + def getPhotoFromRR zekken_number, event_code, num #RR => RouteResult + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + if num <= 60 + table = 'route_result' + else + table = 'route_result_2' + end + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,table ) + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + + list = anytable.find2(where) + result = {} + + if list == nil then + @pgconn.disconnect + return {"result" => "ERROR"} + end + + docpath = set_commonbase() + '/' + event_code + '/' + zekken_number + + if( !Dir.exist?(docpath) )then + if( Dir.mkdir( docpath,0755 ) == 0 ) then + end + end + + list.each { |rec| + for i in 1..num do + begin + if rec["cp#{i}_ph"].include?(s3_domain()) then + extension = result["cp#{i}_ph"].to_s.split('.').last + result["cp#{i}_ph"] = rec["cp#{i}_ph"].gsub(s3_domain(),set_commonbase()).gsub(".#{extension}","_th.#{extension}") + elsif rec["cp#{i}_ph"].include?(set_commonbase()) then + result["cp#{i}_ph"] = rec["cp#{i}_ph"].gsub(set_commonbase(),set_commonbase2()) + else + result["cp#{i}_ph"] = "#{set_commonbase()}/asset/photo_none.png" + end + rescue => e + p "error : #{e}, result[cp#{i}_ph] :#{result["cp#{i}_ph"]}" + result["cp#{i}_ph"] = "#{set_commonbase()}/asset/photo_none.png" + end + if result["cp#{i}_ph"].include?("asset/asset") then + result["cp#{i}_ph"].gsub!('asset/asset', 'asset') + end + if File.exist?(result["cp#{i}_ph"]) == false then + begin + filename = rec["cp#{i}_ph"].split('/').last + fullpath = docpath + '/' + filename + fullpath2 = s3_domain + '/' + URI.encode_www_form_component(event_code, enc=nil) + '/' + zekken_number + '/' + filename + URI.open(fullpath2) do |image| + File.open(fullpath, 'w') do |file| + file.write(image.read) + end + end + extension = filename.split('.').last + + filenameTh = filename.gsub(".#{extension}","_th.#{extension}") + + imageOri = Magick::Image.read(fullpath).first + imageTh = imageOri.scale(image_size_width(), image_size_height()) + imageTh.write("temp/#{filenameTh}") + + nextpath = docpath + '/' + filenameTh + + FileUtils.mv("/var/www/temp/#{filenameTh}",nextpath) + # File.delete(fullpath) + + result["cp#{i}_ph"] = nextpath + rescue => e + p "error : #{e}, rec[cp#{i}_ph] :#{rec["cp#{i}_ph"]}" + result["cp#{i}_ph"] = "#{set_commonbase()}/asset/photo_none.png" + end + end + begin + result["cp#{i}_s"] = rec["cp#{i}_s"].gsub(set_commonbase2(),set_commonbase()) + rescue => e + p "error : #{e}, result[cp#{i}_s] : #{result["cp#{i}_s"]}" + result["cp#{i}_s"] = "#{set_commonbase()}/asset/photo_none.png" + end + if result["cp#{i}_s"].include?("asset/asset") then + result["cp#{i}_s"].gsub!('asset/asset', 'asset') + end + if File.exist?(result["cp#{i}_s"]) == false then + result["cp#{i}_s"] = "#{set_commonbase()}/asset/photo_none.png" + end + end + } + + @pgconn.disconnect + + if result == [] || result == nil then + return {"result" => "ERROR"} + end + + result["result"] = "OK" + + return result + end + + def getZekkenNumberByTeamName team_name, event_code + + puts "team_name=#{team_name}, event_code=#{event_code}" + @pgconn=UserPostgres.new + dbname = set_dbname() + puts "dbname=#{dbname}" + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'team_table' ) + + if team_name.include?("'") then + team_name.gsub!("'","''") + end + + where = "team_name = '#{team_name}' AND event_code = '#{event_code}'" + puts "where = #{where}" + + list = anytable.find2(where) + result = "" + + puts "list = #{list}" + if list == nil then + @pgconn.disconnect + return "no zekken number" + end + + list.each { |rec| + result = rec["zekken_number"] + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return "no zekken number" + end + end + + def get_lat_lng_bounds_for_event_code(event_code) + @pgconn = UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost", "mobilous", 0, dbname) + anytable = UserPostgresTable.new + anytable.useTable(@pgconn, 'gps_detail') + + where = "event_code = '#{event_code}' ORDER BY serial_number" + + list = anytable.find2(where) + p "list: #{list}" + + max_latitude = -Float::INFINITY + min_latitude = Float::INFINITY + max_longitude = -Float::INFINITY + min_longitude = Float::INFINITY + + list.each do |rec| + latitude = rec['latitude'].to_f + longitude = rec['longitude'].to_f + + max_latitude = latitude if latitude > max_latitude + min_latitude = latitude if latitude < min_latitude + max_longitude = longitude if longitude > max_longitude + min_longitude = longitude if longitude < min_longitude + end + + @pgconn.disconnect + + { + max_latitude: max_latitude, + min_latitude: min_latitude, + max_longitude: max_longitude, + min_longitude: min_longitude + } + end + + + def getGpsList zekken_number, event_code, sort = 'ASC' + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'gps_detail' ) + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}' ORDER BY serial_number #{sort}" + + list = anytable.find2(where) + result_list = [] + + if list == nil then + return [] + end + + list.each { |rec| + result_list.push(rec) + } + + @pgconn.disconnect + + if result_list != [] && result_list != nil then + return result_list + else + return [] + end + + end + + def getSerialNumberByCpNumber zekken_number, event_code, cp_number + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'gps_information' ) + + where = "zekken_number = '#{zekken_number}' AND cp_number = #{cp_number}" + + list = anytable.find2(where) + result = "" + + if list == nil then + return "no sn" + end + + list.each { |rec| + result = rec["serial_number"] + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return "no sn" + end + + end + + def getTeamNameByZekkenNumber zekken_number, event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'team_table' ) + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + + list = anytable.find2(where) + result = "" + + list.each { |rec| + result = rec["team_name"] + } + + @pgconn.disconnect + return result + + end + + def getFinalReport zekken_number, event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'report_list' ) + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + + list = anytable.find2(where) + result = "" + + list.each { |rec| + result = rec["report_address"] + } + + @pgconn.disconnect + + if result == "" || result == nil then + return "no report" + end + + return result + + end + + def getTeamList event_code=nil + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'team_table' ) + + if event_code == nil then + where = "0 = 0" + else + where = "event_code = '#{event_code}'" + end + + list = anytable.find2(where) + result = [] + + list.each { |rec| + result.push(rec) + } + + @pgconn.disconnect + + if result == "" || result == nil then + return "no report" + end + + return result + + + end + + def getZekkenNumberByAgentId agent_id + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'agent_login' ) + + where = "agent_id = '#{agent_id}'" + + list = anytable.find2(where) + result = "" + agent_id = "" + + list.each { |rec| + result = rec["zekken_number"] + agent_id = rec["agent_id"] + } + + @pgconn.disconnect + + if result == "" || result == nil then + if agent_id == "" || agent_id == nil then + return "no data" + else + return "no login" + end + end + + return result + end + + def getDataFromDatabase(zekken_number, event_code) + @pgconn = UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost", "mobilous", 0, dbname) + anytable = UserPostgresTable.new + anytable.useTable(@pgconn, 'gps_detail') + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}' ORDER BY serial_number" + + list = anytable.find2(where) + p "list: #{list}" + result = [] + + list.each { |rec| + result.push(rec) + } + + @pgconn.disconnect + result # 返り値としてresultを返す + end + + def getCPlatlngByCPnumber cp_number, event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'checkpoint_table' ) + + where = "cp_number = " + cp_number.to_s + " AND event_code = '#{event_code}'" + + list = anytable.find2(where) + record = {} + + if list == nil then + return {"status" => "no cp error"} + end + + list.each { |rec| + record = rec + } + + @pgconn.disconnect + + result = {} + + if result != "" && result != nil then + result["status"] = "OK" + result["record"] = record + return result + else + return {"status" => "no cp error"} + end + end + + def getEventStartTime event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'event_table' ) + + where = "event_code = '#{event_code}'" + + list = anytable.find2(where) + result = "" + + if list == nil then + return "" + end + + list.each { |rec| + result = rec["start_time"] + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return "" + end + + end + + def getCPNumByPhotoPoint photo_point, event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'checkpoint_table' ) + + where = "photo_point = " + photo_point.to_s + " AND event_code = '#{event_code}'" + + list = anytable.find2(where) + result = "" + + if list == nil then + return "no cp error" + end + + list.each { |rec| + result = rec["cp_number"] + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return "no cp error" + end + end + + def getPhotoPointByCPNum cp_number, event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'checkpoint_table' ) + + where = "cp_number = " + cp_number.to_s + " AND event_code = '#{event_code}'" + + list = anytable.find2(where) + result = "" + + if list == nil then + return "no cp error" + end + + list.each { |rec| + result = rec["photo_point"] + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return "no cp error" + end + end + + def getCheckpointList event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'checkpoint_table' ) + + where = "event_code = '#{event_code}'" + + list = anytable.find2(where) + result_list = [] + + if list == nil then + return [] + end + + list.each { |rec| + result_list.push(rec) + } + + @pgconn.disconnect + + if result_list != [] && result_list != nil then + return result_list + else + return [] + end + + end + + def getMaxUserNumByRSR event_code # RS => rogeSimRecord + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'rogSimRecord' ) + + where = "user_serial = (SELECT max(user_serial) FROM rogSimRecord WHERE event_code = '#{event_code}' )" + + list = anytable.find2(where) + result = "" + + if list == nil then + return 0 + end + + list.each { |rec| + result = rec['user_serial'] + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return 0 + end + + end + + def getMaxNumByRSR userId, event_code # RS => rogeSimRecord + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'rogSimRecord' ) + + where = "serial_number = (SELECT max(serial_number) FROM rogSimRecord WHERE event_code = '#{event_code}' AND user_serial = #{userId} )" + + list = anytable.find2(where) + result = "" + + if list == nil then + return 0 + end + + list.each { |rec| + result = rec['serial_number'] + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return 0 + end + + end + + def getRogSimResult userId, event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'rogSimRecord' ) + + where = "user_serial = '#{userId}' AND event_code = '#{event_code}' ORDER BY serial_number" + + list = anytable.find2(where) + result = [] + + if list == nil then + return [] + end + + count = 0 + + list.each { |rec| + result[count] = {"cp_number" => rec['cp_number']} + count += 1 + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return [] + end + end + + def getPhotoFromRSV userId, event_code, num #RSV => rogeSimView + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + table = 'rogeSimView' + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,table ) + + where = "user_serial = '#{userId}' AND event_code = '#{event_code}'" + + list = anytable.find2(where) + result = {} + + if list == nil then + return {"result" => "ERROR"} + end + + list.each { |rec| + for i in 1..num do + begin + result["cp#{i}_s"] = rec["cp#{i}_s"].gsub(set_commonbase2(),set_commonbase()) + rescue => e + p "error : #{e}, result[cp#{i}_s] : #{result["cp#{i}_s"]}" + result["cp#{i}_s"] = "#{set_commonbase()}/asset/photo_none.png" + end + if result["cp#{i}_s"].include?("asset/asset") then + result["cp#{i}_s"].gsub!('asset/asset', 'asset') + end + if File.exist?(result["cp#{i}_s"]) == false then + result["cp#{i}_s"] = "#{set_commonbase()}/asset/photo_none.png" + end + end + } + + @pgconn.disconnect + + if result == [] || result == nil then + return {"result" => "ERROR"} + end + + result["result"] = "OK" + + return result + end + + def getEventData event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'event_table' ) + + where = "event_code = '#{event_code}'" + + list = anytable.find2(where) + result = {} + + if list == nil then + return "" + end + + list.each { |rec| + result = rec + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return "" + end + + end + + def getMaxNumByCLS # CLS => cp_listsheet + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'cp_listsheet' ) + + where = "serial_number = (SELECT max(serial_number) FROM cp_listsheet)" + + list = anytable.find2(where) + result = "" + + if list == nil then + return 0 + end + + list.each { |rec| + result = rec['serial_number'] + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return 0 + end + + end + + def getNewUserName userId + + response = client.get_profile(userId) + case response + when Net::HTTPSuccess then + contact = JSON.parse(response.body) + + username = contact['displayName'] + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'user_table' ) + + title = ["userid","user_name","create_at","update_at"] + record = {"userid" => userId, "user_name" => username, "create_at" => DateTime.now, "update_at" => DateTime.now} + + sql = anytable.makeInsertKeySet(title,record) + begin + ret = anytable.exec(sql) # true or false + rescue => error + p error + end + + @pgconn.disconnect + + return {"user_name" => username, "zekken_number" => "no zekken number", "event_code" => ""} + else + p "#{ + response.code + } #{ + response.body + }" + return {"user_name" => "get name error"} + end + + end + + def haversine_distance(lat1, lon1, lat2, lon2) + r = 6371 # 地球の半径(km) + phi1 = lat1 * Math::PI / 180 + phi2 = lat2 * Math::PI / 180 + delta_phi = (lat2 - lat1) * Math::PI / 180 + delta_lambda = (lon2 - lon1) * Math::PI / 180 + + a = Math.sin(delta_phi / 2) ** 2 + Math.cos(phi1) * Math.cos(phi2) * Math.sin(delta_lambda / 2) ** 2 + c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)) + + r * c + end + + def calculate_speed_and_type(prev_point, current_point, next_point) + if prev_point && next_point + time_diff = (Time.parse(next_point['create_at']) - Time.parse(prev_point['create_at'])) / 3600.0 # 時間 + distance = haversine_distance(prev_point['latitude'].to_f, prev_point['longitude'].to_f, + next_point['latitude'].to_f, next_point['longitude'].to_f) + speed = distance / time_diff + else + speed = 0 + end + + movement_type = speed < 18 ? "walking/jogging" : "public_transport" + + [speed, movement_type] + end + + def calculate_cumulative_distance(gps_data, index) + distance = 0 + (1..index).each do |i| + distance += haversine_distance(gps_data[i-1]['latitude'].to_f, gps_data[i-1]['longitude'].to_f, + gps_data[i]['latitude'].to_f, gps_data[i]['longitude'].to_f) + end + distance + end + +#==================================== +# DB:SELECT (check) +#==================================== + def checkBuypointSingleRecord zekken_number, event_code, cp_number + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'gps_information' ) + + #buy_pointであり、レコード数が1以下なら重複なしとして扱う + where_relation = " JOIN checkpoint_table AS c ON g.event_code = c.event_code AND g.cp_number = c.cp_number WHERE g.zekken_number = '#{zekken_number}' AND g.event_code = '#{event_code}' AND g.cp_number = '#{cp_number}' AND c.buy_point > 0" + count = nil + list_relation = anytable.find_for_relation(where_relation) + list_relation.each do |row| + count = row["count"] if row.is_a?(Hash) # rowがハッシュであれば + end + if count.to_i == 1 then + return true + else + return false + end + end + + def cpDoubleCheck(zekken_number, event_code, cp_number) # 重複してたらtrue + @pgconn = UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost", "mobilous", 0, dbname) + + anytable = UserPostgresTable.new + anytable.useTable(@pgconn, 'gps_information') + + # 今日の日付のレコードのみをチェック + today = Date.today.to_s + + # buy_pointであり、今日のレコード数が1以下なら重複なしとして扱う + where_relation = " JOIN checkpoint_table AS c ON g.event_code = c.event_code AND g.cp_number = c.cp_number WHERE g.zekken_number = '#{zekken_number}' AND g.event_code = '#{event_code}' AND g.cp_number = '#{cp_number}' AND c.buy_point > 0 AND DATE(g.create_at) = '#{today}'" + count = nil + list_relation = anytable.find_for_relation(where_relation) + list_relation.each do |row| + count = row["count"] if row.is_a?(Hash) # rowがハッシュであれば + end + if count.to_i == 1 then + @pgconn.disconnect + return false + end + + # 今日の日付のレコードをチェック + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}' AND cp_number = '#{cp_number}' AND DATE(create_at) = '#{today}'" + + list = anytable.find2(where) + result = "" + + if list == nil then + @pgconn.disconnect + return false + end + + list.each { |rec| + result = rec["serial_number"] + } + + @pgconn.disconnect + + if result != "" && result != nil then + return true + else + return false + end + end + + # def cpDoubleCheck zekken_number, event_code, cp_number # 重複してたらtrue + + # @pgconn=UserPostgres.new + # dbname = set_dbname() + # @pgconn.connectPg("localhost","mobilous",0,dbname) + + # anytable=UserPostgresTable.new + # anytable.useTable( @pgconn,'gps_information' ) + + # #buy_pointであり、レコード数が1以下なら重複なしとして扱う + # where_relation = " JOIN checkpoint_table AS c ON g.event_code = c.event_code AND g.cp_number = c.cp_number WHERE g.zekken_number = '#{zekken_number}' AND g.event_code = '#{event_code}' AND g.cp_number = '#{cp_number}' AND c.buy_point > 0" + # count = nil + # list_relation = anytable.find_for_relation(where_relation) + # list_relation.each do |row| + # count = row["count"] if row.is_a?(Hash) # rowがハッシュであれば + # end + # if count.to_i == 1 then + # return false + # end + + # where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}' AND cp_number = '#{cp_number}'" + + # list = anytable.find2(where) + # #return list + # #p list + # #return true + # result = "" + + # if list == nil then + # return false + # end + + # list.each { |rec| + # result = rec["serial_number"] + # } + + # @pgconn.disconnect + + # if result != "" && result != nil then + # return true + # else + # return false + # end + + # end + + def zekkenAuthorization zekken,password + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'team_table' ) + + where = "zekken_number = '#{zekken}' AND password = '#{password}'" + + list = anytable.find2(where) + result = {} + + if list == nil then + return { "zekken_number" => "ERROR" } + end + + list.each { |rec| + result["zekken_number"] = rec["zekken_number"] + result["team_name"] = rec["team_name"] + result["event_code"] = rec["event_code"] + } + + @pgconn.disconnect + + if result != {} && result != nil then + result["result"] = "OK" + return result + else + result["result"] = "ERROR" + return result + end + end + + def agentAuthorization password + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'agent_table' ) + + where = "password = '#{password}'" + p "where : #{where}" + list = anytable.find2(where) + result = "" + + if list == nil then + return "ERROR" + end + + list.each { |rec| + result = rec["agent_id"] + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return "ERROR" + end + end + + def checkStatus userId + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'chat_status' ) + + where = "userid = '#{userId}'" + + list = anytable.find2(where) + result = {} + + if list == nil then + result['status'] = "nothing" + return result + end + + list.each { |rec| + result['status'] = rec["status"] + result['memory'] = rec["memory"] + } + + @pgconn.disconnect + + if result != {} && result != nil then + return result + else + result['status'] = "nothing" + return result + end + + end + + def checkAgentFlag zekken_number,event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'agent_flag' ) + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + + list = anytable.find2(where) + result = {} + + if list == nil then + return false + end + + list.each { |rec| + result = rec["agent_id"] + } + + @pgconn.disconnect + + if result != "" && result != nil then + return true + else + return false + end + + end + + def checkBonusPointFlag(zekken_number, event_code) + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost", "mobilous", 0, dbname) + + anytable=UserPostgresTable.new + anytable.useTable(@pgconn, 'bonus_point_flag') + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + + list = anytable.find2(where) + @pgconn.disconnect # データベース接続を切断 + + # ntuplesメソッドを使用して結果セットに含まれる行の数をチェック + if list.ntuples.zero? + return false # レコードが存在しない場合はfalseを返す + else + return true # レコードが1つでも見つかった場合はtrueを返す + end + end + + + + + def checkEventCode event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'event_table' ) + + where = "event_code = '#{event_code}'" + + list = anytable.find2(where) + result = "" + + if list == nil then + return "" + end + + list.each { |rec| + result = rec["event_name"] + } + + @pgconn.disconnect + + if result != "" && result != nil then + return result + else + return "" + end + + end + + def checkZekkenExist zekken_number + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'team_table' ) + + where = "zekken_number = '#{zekken_number}'" + + list = anytable.find2(where) + result = "" + + if list == nil then + return false + end + + list.each { |rec| + result = rec["team_name"] + } + + @pgconn.disconnect + + if result != "" && result != nil then + return true + else + return false + end + + end + + def process_route_data(gps_data, bounds) + width = 800 + height = 600 + + # ルートポイントを正規化 + normalized_points = gps_data.map do |point| + x = (point['longitude'].to_f - bounds[:min_longitude]) * width / (bounds[:max_longitude] - bounds[:min_longitude]) + y = height - (point['latitude'].to_f - bounds[:min_latitude]) * height / (bounds[:max_latitude] - bounds[:min_latitude]) + { + x: x, + y: y, + longitude: point['longitude'].to_f, + latitude: point['latitude'].to_f, + timestamp: point['timestamp'] + } + end + + { + points: normalized_points, + start: normalized_points.first, + end: normalized_points.last, + bounds: bounds + } + end + + # ユーザーのルート情報を取得するメソッド + def get_user_route(pgconn, event_code, zekken_number) + anytable = UserPostgresTable.new + anytable.useTable(pgconn, 'gps_detail') + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}' ORDER BY create_at ASC" + route_data = anytable.find2(where) + + route_data.map do |point| + { + latitude: point['latitude'].to_f, + longitude: point['longitude'].to_f, + timestamp: point['create_at'] + } + end + end + +#==================================== +# DB:INSERT +#==================================== + +# def inputCPnumber zekken_number, event_code, cp_number, image_address, insert_number = 0 + +# if insert_number == 0 then +# next_num = getMaxNumByGI(zekken_number,event_code).to_i + 1 +# else +# next_num = insert_number +# end + +# @pgconn=UserPostgres.new +# dbname = set_dbname() +# @pgconn.connectPg("localhost","mobilous",0,dbname) + +# anytable=UserPostgresTable.new +# anytable.useTable( @pgconn,'gps_information' ) + +# #buy_pointであり、すでに同じcpのレコードが存在しているなら +# where_relation = " JOIN checkpoint_table AS c ON g.event_code = c.event_code AND g.cp_number = c.cp_number WHERE g.zekken_number = '#{zekken_number}' AND g.event_code = '#{event_code}' AND g.cp_number = '#{cp_number}' AND c.buy_point > 0" +# count = nil +# list_relation = anytable.find_for_relation(where_relation) +# list_relation.each do |row| +# count = row["count"] if row.is_a?(Hash) # rowがハッシュであれば +# end +# if count.to_i == 1 then +# title = ["serial_number", "zekken_number","event_code","cp_number","image_address","create_at","update_at","minus_photo_flag"] +# record = {"serial_number" => next_num, "zekken_number" => zekken_number, "event_code" => event_code, "cp_number" => cp_number, "image_address" => image_address,"create_at" => DateTime.now, "update_at" => DateTime.now, "minus_photo_flag" => 'true', "photo_point" => 0} +# sql = anytable.makeInsertKeySet(title,record) +# begin +# #ret = anytable.exec(sql) # true or false +# anytable.insertExec(sql) # true or false +# rescue => error +# p error +# end +# @pgconn.disconnect +# return "200 OK" +# end + +# title = ["serial_number", "zekken_number","event_code","cp_number","image_address","create_at","update_at"] +# record = {"serial_number" => next_num, "zekken_number" => zekken_number, "event_code" => event_code, "cp_number" => cp_number, "image_address" => image_address,"create_at" => DateTime.now, "update_at" => DateTime.now} + +# sql = anytable.makeInsertKeySet(title,record) +# begin +# #ret = anytable.exec(sql) # true or false +# anytable.insertExec(sql) # true or false +# rescue => error +# p error +# end + +# @pgconn.disconnect + +# return "200 OK" + +# end + +def inputCPnumber(zekken_number, event_code, cp_number, image_address, insert_number = 0) + puts "inputCPnumber" + + if insert_number == 0 + next_num = getMaxNumByGI(zekken_number, event_code).to_i + 1 + else + next_num = insert_number + end + + @pgconn = UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost", "mobilous", 0, dbname) + + anytable = UserPostgresTable.new + anytable.useTable(@pgconn, 'gps_information') + + # colabo_company_memoの初期化 + colabo_company_memo = '' + + # 日付チェックと値の設定 + current_date = Date.today + if current_date >= Date.new(2024, 7, 8) && current_date <= Date.new(2024, 10, 31) + colabo_company_memo = "FC岐阜" + end + + # 同じ日付でのチェックポイント数を確認 + today = Date.today.to_s + where_relation = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}' AND DATE(create_at) = '#{today}'" + + # buy_pointが0より大きいチェックポイントの数を確認 + buy_point_count = anytable.count("#{where_relation} AND cp_number IN (SELECT cp_number FROM checkpoint_table WHERE event_code = '#{event_code}' AND buy_point > 0)") + + # photo_pointのみのチェックポイントの数を確認 + photo_point_count = anytable.count("#{where_relation} AND cp_number IN (SELECT cp_number FROM checkpoint_table WHERE event_code = '#{event_code}' AND buy_point = 0)") + + # 現在のcp_numberのbuy_pointを確認 + cp_buy_point_query = "JOIN checkpoint_table c ON g.event_code = c.event_code AND g.cp_number = c.cp_number WHERE g.event_code = '#{event_code}' AND g.cp_number = '#{cp_number}'" + cp_buy_point_result = anytable.find_for_relation(cp_buy_point_query, nil, "c.buy_point") + + current_cp_buy_point = 0 + if cp_buy_point_result && cp_buy_point_result.any? + current_cp_buy_point = cp_buy_point_result.first['buy_point'].to_i + end + + if (current_cp_buy_point > 0 && buy_point_count.to_i >= 2) || (current_cp_buy_point == 0 && photo_point_count.to_i >= 1) + @pgconn.disconnect + return "409 Conflict" # 既に制限に達している場合 + end + + # 同じ日付で同じチェックポイントのレコードが存在するか確認 + same_cp_count = anytable.count("#{where_relation} AND cp_number = '#{cp_number}'") + + if same_cp_count.to_i > 0 + @pgconn.disconnect + return "409 Conflict" # 既に同じ日付で同じチェックポイントのレコードが存在する場合 + end + + title = ["serial_number", "zekken_number", "event_code", "cp_number", "image_address", "create_at", "update_at", "colabo_company_memo"] + record = { + "serial_number" => next_num, + "zekken_number" => zekken_number, + "event_code" => event_code, + "cp_number" => cp_number, + "image_address" => image_address, + "create_at" => DateTime.now, + "update_at" => DateTime.now, + "colabo_company_memo" => colabo_company_memo + } + + sql = anytable.makeInsertKeySet(title, record) + begin + anytable.insertExec(sql) # true or false + rescue => error + p error + @pgconn.disconnect + return "500 Internal Server Error" + end + + @pgconn.disconnect + + return "200 OK" +end + + + + def test_inputCPnumber zekken_number, event_code, cp_number, image_address, insert_number = 0 + + if insert_number == 0 then + next_num = getMaxNumByGI(zekken_number,event_code).to_i + 1 + else + next_num = insert_number + end + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'gps_information' ) + + #buy_pointであり、すでに同じcpのレコードが存在しているなら + where_relation = " JOIN checkpoint_table AS c ON g.event_code = c.event_code AND g.cp_number = c.cp_number WHERE g.zekken_number = '#{zekken_number}' AND g.event_code = '#{event_code}' AND g.cp_number = '#{cp_number}' AND c.buy_point > 0" + count = nil + list_relation = anytable.find_for_relation(where_relation) + list_relation.each do |row| + count = row["count"] if row.is_a?(Hash) # rowがハッシュであれば + end + if count.to_i == 1 then + title = ["serial_number", "zekken_number","event_code","cp_number","image_address","create_at","update_at","minus_photo_flag"] + record = {"serial_number" => next_num, "zekken_number" => zekken_number, "event_code" => event_code, "cp_number" => cp_number, "image_address" => image_address,"create_at" => DateTime.now, "update_at" => DateTime.now, "minus_photo_flag" => 'true'} + sql = anytable.makeInsertKeySet(title,record) + return sql + begin + #ret = anytable.exec(sql) # true or false + anytable.insertExec(sql) # true or false + rescue => error + p error + end + @pgconn.disconnect + return "200 OK" + end + + title = ["serial_number", "zekken_number","event_code","cp_number","image_address","create_at","update_at"] + record = {"serial_number" => next_num, "zekken_number" => zekken_number, "event_code" => event_code, "cp_number" => cp_number, "image_address" => image_address,"create_at" => DateTime.now, "update_at" => DateTime.now} + + sql = anytable.makeInsertKeySet(title,record) + begin + #ret = anytable.exec(sql) # true or false + anytable.insertExec(sql) # true or false + rescue => error + p error + end + + @pgconn.disconnect + + return "200 OK" + + end + + + def inputStatus userId, status, memory + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'chat_status' ) + + title = ["userid", "status", "memory", "create_at", "update_at"] + record = {"userid" => userId, "status" => status, "memory" => memory, "create_at" => DateTime.now, "update_at" => DateTime.now } + + sql = anytable.makeInsertKeySet(title,record) + begin + ret = anytable.exec(sql) # true or false + rescue => error + p error + end + + @pgconn.disconnect + + return "OK" + + end + + def inputGPSlog zekken_number, event_code, lat, lon + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'gpslogger_data' ) + + title = ["zekken_number","event_code","latitude","longitude","point_category","create_at","update_at"] + record = {"zekken_number" => zekken_number, "event_code" => event_code, "latitude" => lat, "longitude" => lon, "point_category" => "route", "create_at" => DateTime.now, "update_at" => DateTime.now} + + sql = anytable.makeInsertKeySet(title,record) + begin + ret = anytable.exec(sql) # true or false + rescue => error + p error + end + + @pgconn.disconnect + + return "200 OK" + + end + + def inputGoalTime zekken_number, event_code, goal_time, late_point,goal_photo + + sn = getMaxNumByGI(zekken_number, event_code).to_i + 1 + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'gps_information' ) + + title = ["serial_number","zekken_number","event_code","cp_number","image_address","goal_time","late_point","create_at","update_at"] + record = {"serial_number" => sn, "zekken_number" => zekken_number, "event_code" => event_code, "cp_number" => -1,"image_address" => goal_photo, "goal_time" => goal_time, "late_point" => late_point, "create_at" => DateTime.now, "update_at" => DateTime.now} + + sql = anytable.makeInsertKeySet(title,record) + begin + ret = anytable.exec(sql) # true or false + rescue => error + p error + end + + @pgconn.disconnect + + return "200 OK" + + end + + def inputAgentLogin agent_id, zekken_number, event_code + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'agent_login' ) + + title = ["agent_id", "zekken_number","event_code","create_at","update_at"] + record = {"agent_id" => agent_id, "zekken_number" => zekken_number, "event_code" => event_code, "create_at" => DateTime.now, "update_at" => DateTime.now} + + sql = anytable.makeInsertKeySet(title,record) + begin + ret = anytable.exec(sql) # true or false + rescue => error + p error + end + + @pgconn.disconnect + end + + def inputFinalReport zekken_number, event_code, pdf_address + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'report_list' ) + + title = ["zekken_number", "event_code", "report_address"] + record = {"zekken_number" => zekken_number, "event_code" => event_code, "report_address" => pdf_address} + + sql = anytable.makeInsertKeySet(title,record) + begin + ret = anytable.exec(sql) # true or false + rescue => error + p error + end + + @pgconn.disconnect + + return "200 OK" + end + + def inputAgentFlag zekken_number, event_code, agent_id + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'agent_flag' ) + + title = ["zekken_number", "agent_id", "event_code", "create_at", "update_at"] + record = {"zekken_number" => zekken_number, "agent_id" => agent_id, "event_code" => event_code, "create_at" => DateTime.now, "update_at" => DateTime.now } + + sql = anytable.makeInsertKeySet(title,record) + begin + ret = anytable.exec(sql) # true or false + rescue => error + p error + end + + @pgconn.disconnect + + end + + def inputTeamData event_code,class_name,zekken_number,team_name,pass + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'team_table' ) + + title = ["zekken_number", "event_code", "team_name", "class_name", "password"] + record = {"zekken_number" => zekken_number, "event_code" => event_code, "team_name" => team_name, "class_name" => class_name, "password" => pass } + + sql = anytable.makeInsertKeySet(title,record) + begin + ret = anytable.exec(sql) # true or false + rescue => error + p error + end + + @pgconn.disconnect + + end + + def inputRogSimRecord userId, event_code, cp_number, insert_number = 0 + + if insert_number == 0 then + next_num = getMaxNumByRSR(userId,event_code).to_i + 1 + else + next_num = insert_number + end + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'rogSimRecord' ) + + title = ["serial_number", "user_serial","event_code","cp_number","create_at"] + record = {"serial_number" => next_num, "user_serial" => userId, "event_code" => event_code, "cp_number" => cp_number, "create_at" => DateTime.now} + + sql = anytable.makeInsertKeySet(title,record) + begin + ret = anytable.exec(sql) # true or false + rescue => error + p error + end + + @pgconn.disconnect + + return "200 OK" + + end + + def inputCpListSheet header, record + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'cp_listsheet' ) + + sql = anytable.makeInsertKeySet(header,record) + begin + ret = anytable.insertExec(sql) # true or false + rescue => error + p error + end + + @pgconn.disconnect + + return "200 OK" + + end + + def inputPrintQueueMemory queue + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'print_queue_memory' ) + + title = ["queue_detail", "add_datetime"] + record = {"queue_detail" => queue, "add_datetime" => DateTime.now} + + sql = anytable.makeInsertKeySet(title,record) + begin + ret = anytable.insertExec(sql) # true or false + rescue => error + p error + end + + @pgconn.disconnect + + return "200 OK" + + end + +#==================================== +# DB:UPDATE (add) +#==================================== + + def addPhotoToGPS serial_number, photoURI + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + rec = {"image_address" => photoURI, "update_at" => DateTime.now} + where = "serial_number = " + serial_number + + begin + @pgconn.update("gps_information",rec,where) + rescue => e + p e + message = { + type: 'text', + text: "写真データの保存に失敗しました。大変申し訳ありませんが、もう一度やり直して下さい。" + } + client.reply_message(event['replyToken'], message) + + @pgconn.disconnect + + return "UPDATE ERROR" + end + + @pgconn.disconnect + + end + + def addUserData userId, zekken_number, event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + rec = {"zekken_number" => zekken_number, "event_code" => event_code,"update_at" => DateTime.now} + where = "userid = '#{userId}'" + + begin + @pgconn.update("user_table",rec,where) + rescue => e + p e + + @pgconn.disconnect + + return "UPDATE ERROR" + end + + @pgconn.disconnect + + return "200 OK" + + end + + def addBuyFlagTrue serial_number, zekken_number, event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + rec = {"buy_flag" => true, "update_at" => DateTime.now} + where = "event_code = '#{event_code}' AND zekken_number = '#{zekken_number}' AND serial_number = #{serial_number}" + + begin + @pgconn.update("gps_information",rec,where) + rescue => e + p e + + @pgconn.disconnect + + return "UPDATE ERROR" + end + + @pgconn.disconnect + + return "OK" + + end + + def addBuyFlagFalse serial_number, zekken_number, event_code + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + rec = {"buy_flag" => false, "update_at" => DateTime.now} + where = "event_code = '#{event_code}' AND zekken_number = '#{zekken_number}' AND serial_number = #{serial_number}" + + begin + @pgconn.update("gps_information",rec,where) + rescue => e + p e + + @pgconn.disconnect + + return "UPDATE ERROR" + end + + @pgconn.disconnect + + return "OK" + + end + +#==================================== +# DB:UPDATE (change) +#==================================== + + def changeSerialNumberInGPSInformation zekken_number, event_code, serial_number, new_serial_number + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + rec = {"serial_number" => new_serial_number, "update_at" => DateTime.now} + where = "serial_number = #{serial_number} AND zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + + begin + @pgconn.update("gps_information",rec,where) + rescue => e + p e + + @pgconn.disconnect + + return "UPDATE ERROR" + end + + @pgconn.disconnect + + return "OK" + + end + + def changeGoalTimeAndLatePoint zekken_number, event_code, goal_time, late_point + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + rec = {"goal_time" => goal_time, "late_point" => late_point, "update_at" => DateTime.now} + where = "zekken_number = '#{zekken_number}' AND cp_number = -1 AND event_code = '#{event_code}'" + + begin + @pgconn.update("gps_information",rec,where) + rescue => e + p e + + @pgconn.disconnect + + return "UPDATE ERROR" + end + + @pgconn.disconnect + + return "OK" + + end + + def changeAgentLogin agent_id, zekken_number, event_code + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + rec = {"zekken_number" => zekken_number, "event_code" => event_code, "update_at" => DateTime.now} + where = "agent_id = '#{agent_id}'" + + begin + @pgconn.update("agent_login",rec,where) + rescue => e + p e + + @pgconn.disconnect + + return "UPDATE ERROR" + end + + @pgconn.disconnect + + return "OK" + end + + def changeFinalReport zekken_number, event_code, pdf_address + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + rec = {"report_address" => pdf_address} + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + + begin + @pgconn.update("report_list",rec,where) + rescue => e + p e + + @pgconn.disconnect + + return "UPDATE ERROR" + end + + @pgconn.disconnect + + return "OK" + + end + + def changeTeamClass zekken_number, event_code, new_class + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + rec = {"class_name" => new_class} + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + + begin + @pgconn.update("team_table",rec,where) + rescue => e + p e + + @pgconn.disconnect + + return "ERROR" + end + + @pgconn.disconnect + + return "OK" + + end + +#==================================== +# DB:DELETE +#==================================== + + def removeGI zekken_number, event_code, serial_number #GI => gps_information + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'gps_information' ) + + where = "serial_number = #{serial_number} AND zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + + begin + p anytable.remove(where) + + @pgconn.disconnect + + return "200 OK" + rescue => e + p e + return "delete error" + end + + end + + def removeAllGI zekken_number, event_code #GI => gps_information + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'gps_information' ) + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + + begin + p anytable.remove(where) + anytable.remove(where) + @pgconn.disconnect + + return "200 OK" + rescue => e + return "delete error" + end + + end + + def removeStatus userId #GI => gps_information + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'chat_status' ) + + where = "userid = '#{userId}'" + + begin + p anytable.remove(where) + + @pgconn.disconnect + + + return "200 OK" + rescue => e + return "delete error" + end + + end + +#==================================== +# RogSim +#==================================== + + def rogainingSimulator event_code, course_time, pause_time_free, pause_time_paid, spare_time, target_velocity, free_node_to_visit, paid_node_to_visit + p "target_velocity : #{target_velocity}" + input_hash = { + 'course_time' => course_time, + 'pause_time_free' => pause_time_free, + 'pause_time_paid' => pause_time_paid, + 'spare_time' => spare_time, + 'target_velocity' => target_velocity, + 'free_node_to_visit' => free_node_to_visit, + 'paid_node_to_visit' => paid_node_to_visit + } + p "input_hash : #{input_hash}" + input_json = JSON.generate(input_hash) + + file_origin = set_rogSimBase() + "/work" + + file_name = DateTime.now.to_s.gsub(':','-').gsub('+','_') + '.json' + + file_path = file_origin + "/input/" + file_name + + File.open(file_path, "w") do |f| + f.write(input_json) + end + + system("bash #{set_rogSimBase()}/rogeSim.sh #{event_code} #{file_name}") + + begin + response = {"status" => "OK", "detail" => JSON.parse(File.read(file_origin + "/output/" + file_name))} + rescue Errno::ENOENT => e + response = {"status" => "ERROR", "detail" => "File not found."} + rescue => e + response = {"status" => "ERROR", "detail" => e} + end + + return response + + end + +#==================================== +# Register +#==================================== + + def cpNumberRegister userId, zekken_number, event_code, cp_number, slice_number, client, event + + if slice_number != 0 then + cp_number.slice!(0,slice_number) + end + + if (cp_number.to_s.start_with?('#')) then + cp_number.delete_prefix!('#') + end + + cp_number = cp_number.to_i + + if cp_number <= 0 then + message = { + type: 'text', + text: text_errorCPnumber() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_errorCPnumber()) + return "200 OK" + end + + + cp_number = cp_number.to_i + + if cp_number <= 0 then + message = { + type: 'text', + text: text_errorNoCP(cp_number) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_errorNoCP(cp_number)) + return "200 OK" + end + + cp_name = getCPname(cp_number, event_code) + + if cp_name == "no cp error" then + message = { + type: 'text', + text: text_errorNoCP(cp_number) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_errorNoCP(cp_number)) + + return "200 OK" + end + + if cpDoubleCheck(zekken_number, event_code, cp_number) then + message = { + type: 'text', + text: text_registredCP(cp_number,cp_name) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_registredCP(cp_number,cp_name)) + return "200 OK" + end + + inputStatus(userId,'cp_stanby',cp_number) + + + message = { + type: 'text', + text: text_getCPnumber(cp_number, cp_name) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_getCPnumber(cp_number, cp_name)) + + return "200 OK" + end + + def zekkenNumberRegister userId, zekken_number, event_code, slice_number, client, event + + zekken_number.slice!(0,slice_number) + + if zekken_number.start_with?('[') then + zekken_number.delete_prefix!("[") + end + if zekken_number.end_with?("]") then + zekken_number.delete_suffix!("]") + end + + for i in 1 .. 5 do + if zekken_number.end_with?("-#{i}") then + zekken_number.chop! + zekken_number.chop! + end + end + + if (checkZekkenExist(zekken_number) == false) then + message = { + type: 'text', + text: text_noZekkenNumber() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_noZekkenNumber()) + return "200 OK" + end + + inputStatus(userId, "zekkenAuthorization", zekken_number) + + message = { + type: 'text', + text: text_zekkenRegister(zekken_number) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_zekkenRegister(zekken_number)) + return "200 OK" + + end + + def goalRegister userId, zekken_number, event_code, goal_time, slice_number, client, event + + if cpDoubleCheck(zekken_number, event_code, -1) then + message = { + type: 'text', + text: text_alreadyGoal() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_alreadyGoal()) + return "200 OK" + end + + goal_time.slice!(0,slice_number) + + if zekken_number.start_with?('[') then + zekken_number.delete_prefix!("[") + end + if zekken_number.end_with?("]") then + zekken_number.delete_suffix!("]") + end + + if goal_time.include?('時') then + goal_time.gsub!(/時/, ':') + end + if goal_time.include?('秒') then + goal_time.delete_suffix!("秒") + goal_time.gsub!(/分/, ':') + end + if goal_time.include?('分') then + goal_time.delete_suffix!("分") + end + + if goal_time.end_with?(':') then + message = { + type: 'text', + text: text_goalError() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_goalError()) + return "200 OK" + end + + begin + goaltime = Time.parse(goal_time) + rescue => error + p error + message = { + type: 'text', + text: text_goalError() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_goalError()) + return "200 OK" + end + + result = getTeamDataByZekken_number(zekken_number, event_code) + + starttime = Time.parse(getEventStartTime(event_code)) + + if result['class_name'].include?('3時間') then + limittime = starttime + (3 * 60 * 60) + elsif result['class_name'].include?('5時間') then + limittime = starttime + (5 * 60 * 60) + elsif result['class_name'].include?("テスト") || result['class_name'].include?("test") then + #elsif result['class_name'] == "test" || result['class_name'] == "test2" then + limittime = starttime + (5 * 60 * 60) + else + message = { + type: 'text', + text: 'エラーコード:DBS-001\nチーム情報の取得に失敗しました。\nゼッケン番号とこのエラーコードを添えて運営に問い合わせて下さい。' + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', 'エラーコード:DBS-001\nチーム情報の取得に失敗しました。\nゼッケン番号とこのエラーコードを添えて運営に問い合わせて下さい。') + return "200 OK" + end + + if limittime < goaltime then + late_point = goaltime - limittime + if late_point < 60 + late_point = 50 + else + late_point = late_point/60 + 1 + late_point = late_point.floor*50 + end + else + late_point = 0 + end + + data = {"goal_time" => goal_time, "late_point" => late_point} + + jdata = JSON.generate(data) + + inputStatus(userId,'goal_stanby',jdata) + + message = { + type: 'text', + text: text_getGoal(goal_time) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_getGoal(goal_time)) + + return "200 OK" + end + + def agentRegister userId, command, client, event + p "agentR command : #{command}" + commandAr = command.split(' ') + + agent_id = agentAuthorization(commandAr[1]) + + if (agent_id == "ERROR") then + message = { + type: 'text', + text: text_notAgent() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_notAgent()) + return "200 OK" + else + end + + event_code = commandAr[2] + + event_name = checkEventCode(event_code) + + if event_name == "" then + message = { + type: 'text', + text: text_noEventName() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_noEventName()) + + return "200 OK" + end + + result = addUserData(userId,agent_id,event_code) + if result == "UPDATE ERROR" then + message = { + type: 'text', + text: "エラーコード:USR-002\nログインには成功しましたが、チーム情報の紐付けに失敗しました。\n恐れ入りますが、時間をあけて再度パスワードを御入力頂けますでしょうか。\n※このエラーが何度も発生する場合、エラーコード、LINEのユーザー名を添えて、運営に問い合わせて下さい。" + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', "エラーコード:USR-002\nログインには成功しましたが、チーム情報の紐付けに失敗しました。\n恐れ入りますが、時間をあけて再度パスワードを御入力頂けますでしょうか。\n※このエラーが何度も発生する場合、エラーコード、LINEのユーザー名を添えて、運営に問い合わせて下さい。") + return "200 OK" + end + + message = { + type: 'text', + text: text_agentStart(event_name) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_agentStart(event_name)) + + return "200 OK" + + end + + def checkinRegister userId, command, agent_id, event_code, client, event + + commandAr = command.split(' ') + zekken_number = commandAr[1] + + teamData = getTeamDataByZekken_number(zekken_number, event_code) + + if teamData['result'] == "ERROR" then + message = { + type: 'text', + text: text_zekkenNotExist(zekken_number) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_agentStart(zekken_number)) + return "200 OK" + end + + result = getZekkenNumberByAgentId(agent_id) + + if result == "no data" then + inputAgentLogin(agent_id,zekken_number,event_code) + else + changeAgentLogin(agent_id,zekken_number,event_code) + end + + if (checkAgentFlag(zekken_number, event_code) == false) then + + inputAgentFlag(zekken_number, event_code, agent_id) + + end + + message = { + type: 'text', + text: text_agentLogin(teamData["team_name"]) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_agentLogin(teamData["team_name"])) + return "200 OK" + + end + + def checkoutRegister userId, agent_id, event_code, client, event + + + result = getZekkenNumberByAgentId(agent_id) + + if result == "no login" || result == "no data" then + return "200 OK" + end + + changeAgentLogin(agent_id,"","") + + message = { + type: 'text', + text: text_agentLogout() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_agentLogout()) + return "200 OK" + + end + + def insertTentativeRegister userId, zekken_number, event_code, command, client, event + + commandAr = command.split(' ') + + insert_number = commandAr[1].to_i + + cp_number = commandAr[2].to_i + + if insert_number == "" || cp_number == "" then + message = { + type: 'text', + text: text_argumentError_Insert() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_argumentError_Insert()) + return "200 OK" + end + + if insert_number <= 0 then + message = { + type: 'text', + text: text_notNaturakNumber() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_notNaturakNumber()) + return "200 OK" + end + + if cp_number <= 0 then + message = { + type: 'text', + text: text_errorCPnumber() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_errorCPnumber()) + return "200 OK" + end + + photo_point = 0 + if cp_number < 996 then + photo_point = getPhotoPointByCPNum(cp_number,event_code) + if cp_number == "no cp error" then + message = { + type: 'text', + text: text_errorNoCP(cp_number) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_errorNoCP(cp_number)) + end + end + + if cp_number <= 0 then + message = { + type: 'text', + text: text_errorNoCP(cp_number) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_errorNoCP(cp_number)) + return "200 OK" + end + + jdata = JSON.generate({"insert_number" => insert_number, "cp_number" => cp_number, "photo_point" => photo_point}) + + cp_name = getCPname(cp_number, event_code) + + if cp_name == "no cp error" then + message = { + type: 'text', + text: text_errorNoCP(cp_number) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_errorNoCP(cp_number)) + return "200 OK" + end + + if (cpDoubleCheck(zekken_number, event_code, cp_number)) then + message = { + type: 'text', + text: text_registredCP(cp_number,cp_name) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_registredCP(cp_number,cp_name)) + return "200 OK" + end + + inputStatus(userId, "insert", jdata) + + message = { + type: 'text', + text: text_getCPnumber(cp_number, cp_name) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_getCPnumber(cp_number, cp_name)) + return "200 OK" + end + + def insertRegister userId, zekken_number, event_code, jdata, image, client, event + + data = JSON.parse(jdata) + + insert_number = data["insert_number"] + cp_number = data["cp_number"] + photo_point = data["photo_point"] + + cp_name = getCPname(cp_number, event_code) + + if (cpDoubleCheck(zekken_number, event_code, cp_number)) then + message = { + type: 'text', + text: text_registredCP(cp_number,cp_name) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_registredCP(cp_number,cp_name)) + return "200 OK" + end + + gps_list = getGpsList(zekken_number, event_code, "DESC") + + gps_list.each{ |rec| + + sn = rec["serial_number"] + + result = changeSerialNumberInGPSInformation(zekken_number, event_code, sn, sn.to_i + 1) + + if sn.to_i == insert_number.to_i then + break + end + + } + + inputCPnumber(zekken_number, event_code, cp_number, image, insert_number) + + result = removeStatus(userId) + if result == "delete error" then + for i in 1..10 do + result = removeStatus(userId) + if result == "200 OK" then + break + end + end + end + + if result == "delete error" + message = { + type: 'text', + text: text_importantError("STA-002") + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_importantError("STA-002")) + return "200 OK" + end + + message = { + type: 'text', + text: text_insertComplete(cp_number,cp_name,insert_number) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_insertComplete(cp_number,cp_name,insert_number)) + + return "200 OK" + + end + + def deleteRegister userId, zekken_number, event_code, command, client, event, api_flag = false + commandAr = command.split(' ') + + c_sn = commandAr[1] + + removeGI(zekken_number, event_code, c_sn) + + gps_list = getGpsList(zekken_number,event_code, "ASC") + + gps_list.each{ |rec| + + sn = rec["serial_number"] + + if sn.to_i > c_sn.to_i then + result = changeSerialNumberInGPSInformation(zekken_number, event_code, sn, sn.to_i - 1) + end + + } + + if api_flag == true then + return "OK" + end + message = { + type: 'text', + text: text_deleteCP(c_sn) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_deleteCP(c_sn)) + return "200 OK" + + end + + + def moveRegister userId, zekken_number, event_code,command, client, event, api_flag = false + + commandAr = command.split(' ') + old_sn = commandAr[1] + new_sn = commandAr[2] + + max_sn = getMaxNumByGI(zekken_number,event_code) + + p "max_sn : #{max_sn}, old_sn : #{old_sn}, new_sn : #{new_sn}" + + if new_sn.to_i > max_sn.to_i || old_sn.to_i > max_sn.to_i then + p "over num error" + + if api_flag then + return "over num error" + end + + message = { + type: 'text', + text: text_moveOverNum() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_moveOverNum()) + return "200 OK" + + end + + if old_sn.to_i == new_sn.to_i then + p "same num error" + + if api_flag then + return "same num error" + end + + message = { + type: 'text', + text: text_moveSameNum() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_moveSameNum()) + return "200 OK" + + end + + changeSerialNumberInGPSInformation(zekken_number, event_code, old_sn, -1) + + gps_list = getGpsList(zekken_number, event_code, "ASC") + + gps_list.each{ |rec| + + sn = rec["serial_number"] + + if sn.to_i > old_sn.to_i then + result = changeSerialNumberInGPSInformation(zekken_number, event_code, sn.to_i, sn.to_i - 1) + end + + } + + if new_sn.to_i == max_sn.to_i then + + else + + gps_list = getGpsList(zekken_number, event_code, "DESC") + + gps_list.each{ |rec| + + sn = rec["serial_number"] + + result = changeSerialNumberInGPSInformation(zekken_number, event_code, sn.to_i, sn.to_i + 1) + + if sn.to_i == new_sn.to_i then + break + end + + } + + end + + changeSerialNumberInGPSInformation(zekken_number, event_code, -1, new_sn.to_i) + + if api_flag then + return "OK" + end + + message = { + type: 'text', + text: text_moveCP(old_sn, new_sn) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_moveCP(old_sn, new_sn)) + return "200 OK" + + end + + def timeChRegister userId, zekken_number, event_code, command, client, event + commandAr = command.split(' ') + + goal_time = commandAr[1] + + if zekken_number.start_with?('[') then + zekken_number.delete_prefix!("[") + end + if zekken_number.end_with?("]") then + zekken_number.delete_suffix!("]") + end + + if goal_time.include?('時') then + goal_time.gsub!(/時/, ':') + end + if goal_time.include?('秒') then + goal_time.delete_suffix!("秒") + goal_time.gsub!(/分/, ':') + end + if goal_time.include?('分') then + goal_time.delete_suffix!("分") + end + + if goal_time.end_with?(':') then + message = { + type: 'text', + text: text_goalError() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_goalError()) + return "200 OK" + end + + begin + goaltime = Time.parse(goal_time) + rescue => error + p error + message = { + type: 'text', + text: text_goalError() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_goalError()) + return "200 OK" + end + + result = getTeamDataByZekken_number(zekken_number, event_code) + + starttime = Time.parse(getEventStartTime(event_code)) + + if result['class_name'].include?('3時間') then + limittime = starttime + (3 * 60 * 60) + elsif result['class_name'].include?('5時間') then + limittime = starttime + (5 * 60 * 60) + elsif result['class_name'].include?("テスト") || result['class_name'].include?("test") then + #elsif result['class_name'] == "test" then + limittime = starttime + (5 * 60 * 60) + else + message = { + type: 'text', + text: 'エラーコード:DBS-001\nチーム情報の取得に失敗しました。\nゼッケン番号とこのエラーコードを添えて運営に問い合わせて下さい。' + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', 'エラーコード:DBS-001\nチーム情報の取得に失敗しました。\nゼッケン番号とこのエラーコードを添えて運営に問い合わせて下さい。') + return "200 OK" + end + + if limittime < goaltime then + late_point = goaltime - limittime + if late_point < 60 + late_point = 50 + else + late_point = late_point/60 + 1 + late_point = late_point.floor*50 + end + else + late_point = 0 + end + + result = changeGoalTimeAndLatePoint(zekken_number, event_code, goal_time, late_point) + + if result == "UPDATE ERROR" then + message = { + type: 'text', + text: "システム的なエラーにより時刻の更新に失敗しました。もう一度やり直すか、このエラーが連続する場合、システム管理者に連絡してください。" + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', "システム的なエラーにより時刻の更新に失敗しました。もう一度やり直すか、このエラーが連続する場合、システム管理者に連絡してください。") + return "200 OK" + end + + message = { + type: 'text', + text: text_goalUpdate(goal_time) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_goalUpdate(goal_time)) + return "200 OK" + + end + + def reprinter userId, zekken_number, event_code, client, event + + message = { + type: 'text', + text: text_reprint() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_reprint()) + + Thread.new do + makeScoreboardThread(zekken_number, event_code, "true") + end + + end + + def listUpper userId, zekken_number, event_code, client, event + + origin_list = getGpsList(zekken_number, event_code, "ASC") + + message_text = "チェックポイント通過リスト\n" + + origin_list.each { |rec| + if rec["cp_number"].to_i == -1 then + message_text += "【#{rec["serial_number"]}】ゴールタイム:#{rec["goal_time"]} 減点:#{rec["late_point"]}" + break + else + if rec["buy_point"].to_i == 0 then + point = rec["photo_point"] + else + point = rec["buy_point"] + end + message_text += "【#{rec["serial_number"]}】#{rec["cp_number"]}:#{rec["cp_name"]} 得点:#{point}\n" + end + } + + message = { + type: 'text', + text: message_text + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', message_text) + + return "200 OK" + + end + + def startRegister userId, zekken_number, client, event + inputStatus(userId, "start", "nil") + + message = { + type: 'text', + text: text_startStand() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_startStand()) + return "200 OK" + end + +#==================================== +# Scoreboard +#==================================== + + def makeScoreboardThread zekken_number, event_code, reprintF = false, budleF = false + + item = {"zekken_number" => zekken_number, "event_code" => event_code, "reprintF" => reprintF} + + itemJSON = JSON.generate(item) + + p "queue add : #{itemJSON}" + + inputPrintQueueMemory(itemJSON) + + $queue << itemJSON + + end + + def makeScoreboard zekken_number, event_code, reprintF = false, budleF = false + filepath = getScoreboardGeneral(zekken_number, event_code) + + if filepath == "no_data" then + return "no data error" + end + + if reprintF then + date_memory = DateTime.now.to_s.gsub(':','-').gsub('+','_') + nextpath = set_commonbase() + "/#{event_code}" + "/scoreboard/#{zekken_number}_scoreboard_" + date_memory + ".xlsx" + else + nextpath = set_commonbase() + "/#{event_code}" + "/scoreboard/#{zekken_number}_scoreboard.xlsx" + end + + if( !Dir.exist?(set_commonbase() + "/#{event_code}" + "/scoreboard") )then + if( Dir.mkdir( set_commonbase() + "/#{event_code}" + "/scoreboard",0755 ) == 0 ) then + #p "mkdir #{commonbase}" + end + end + + FileUtils.mv(filepath,nextpath) + + docpath_user = set_commonbase() + "/#{event_code}" + "/scoreboard" + pdffile = "#{zekken_number}_scoreboard" + + if reprintF then + pdffile = pdffile + '_' + date_memory + end + + command ="/home/mobilousInstance/jodconverter-cli-4.4.5-SNAPSHOT/bin/jodconverter-cli -o #{docpath_user}/#{pdffile}.xlsx #{docpath_user}/#{pdffile}.pdf" #郡上のイベント後はこちらの仕様に置き換える + system( command ) + puts command + #system("echo 'sumasen@123' |sudo -S /var/www/lib/generatePDF.sh #{docpath_user} #{pdffile}") + + aws_url = s3Uploader("#{event_code}/scoreboard", docpath_user, pdffile + '.pdf') + + if getFinalReport(zekken_number, event_code) == "no report" then + inputFinalReport(zekken_number, event_code, aws_url) + else + changeFinalReport(zekken_number, event_code, aws_url) + end + + # File.delete(nextpath) + if budleF == false then + # File.delete(nextpath.gsub('.xlsx','.pdf')) + return nextpath.gsub('.xlsx','.pdf') + end + end + + def getScoreboardGeneral zekken_number, event_code + #usernameエラーで引っかかる + # + #$bean.read_bean + #username = $bean.username + username = 'test' + + record = {} + + record["zekken_number"] = zekken_number + + result = getGpsInfo(zekken_number, event_code) + + if result == [] then + return "no_data" + end + + count = 0 + + result.each { |rec| + count += 1 + } + + result2 = getPhotoFromRR(zekken_number, event_code, count) + + if result2 == {} || result2["result"] == "ERROR" then + + return "no_data" + + end + + record.merge!(result2) + + if count <= 60 then + document = "scoreboardGeneral" + else + document = "scoreboardGeneral2" + end + + count = count * 2 + 1 + + record["num_image"] = count + + ExcelObject.resetClass + + doc = AppExeExcelDoc.new + #doc = AppExeGeneralDocument.new + doc.init( username,0,document,"jp","/var/www/docbase","/home/mobilousInstance" ) # <== "/home/mobilousInstance" を出力先のベースフォルダーにしてください。 + + pgconn=UserPostgres.new + dbname = set_dbname() + pgconn.connectPg("localhost","mobilous",0,dbname) + + rec = JSON.parse( JSON.generate(record) ) + #@sheetname = sheet + #filename = doc.makeReport( pgconn,rec,"outfile.xlsx",0 ) # ==> Use ini file defnition 2021-11-15 + doc.makeReport( pgconn,rec ) + + # make a excel file under /var/www/docbase/(@username)/(@projectno)/ + + #file_path = filename.to_s.gsub(/wrote excel file on /,"") + #puts "=========> file_path = #{file_path}" + + filename = doc.outfile + file_path = doc.outpath + puts "=========> file_path = #{file_path}, filename = #{filename}" + + return file_path + + end + +#==================================== +# rogSimResult +#==================================== + + def makeRogSimResultSheet userId, event_code + filepath = getRogSimResultSheet(userId, event_code) + + if filepath == "no_data" then + return "no data error" + end + + nextpath = set_commonbase() + "/#{event_code}" + "/rogeSimResult/#{userId}_rogeSimResult_#{DateTime.now.to_s.gsub(':','-').gsub('+','_')}.xlsx" + + if( !Dir.exist?(set_commonbase() + "/#{event_code}" + "/rogeSimResult") )then + if( Dir.mkdir( set_commonbase() + "/#{event_code}" + "/rogeSimResult",0755 ) == 0 ) then + #p "mkdir #{commonbase}" + end + end + + FileUtils.mv(filepath,nextpath) + + docpath_user = set_commonbase() + "/#{event_code}" + "/rogeSimResult" + pdffile = "#{userId}_rogeSimResult_#{DateTime.now.to_s.gsub(':','-').gsub('+','_')}" + + command ="/home/mobilousInstance/jodconverter-cli-4.4.5-SNAPSHOT/bin/jodconverter-cli -o #{docpath_user}/#{pdffile}.xlsx #{docpath_user}/#{pdffile}.pdf" #郡上のイベント後はこちらの仕様に置き換える + system( command ) + puts command + #system("echo 'sumasen@123' |sudo -S /var/www/lib/generatePDF.sh #{docpath_user} #{pdffile}") + + aws_url = s3Uploader("#{event_code}/rogeSimResult", docpath_user, pdffile + '.pdf') + + return aws_url + end + + def getRogSimResultSheet userId, event_code + #usernameで引っかかる + #$bean.read_bean + #username = $bean.username + username = 'test' + + record = {} + + record["user_serial"] = userId + record["event_code"] = event_code + + result = getRogSimResult(userId, event_code) + + if result == [] then + return "no_data" + end + + count = 0 + + result.each { |rec| + count += 1 + } + + result2 = getPhotoFromRSV(userId, event_code, count) + + if result2 == {} || result2["result"] == "ERROR" then + + return "no_data" + + end + + record.merge!(result2) + + document = "rogeSimResult" + + count = count + 1 + + record["num_image"] = count + + ExcelObject.resetClass + + doc = AppExeExcelDoc.new + #doc = AppExeGeneralDocument.new + doc.init( username,0,document,"jp","/var/www/docbase","/home/mobilousInstance" ) # <== "/home/mobilousInstance" を出力先のベースフォルダーにしてください。 + + pgconn=UserPostgres.new + dbname = set_dbname() + pgconn.connectPg("localhost","mobilous",0,dbname) + + rec = JSON.parse( JSON.generate(record) ) + #@sheetname = sheet + #filename = doc.makeReport( pgconn,rec,"outfile.xlsx",0 ) # ==> Use ini file defnition 2021-11-15 + doc.makeReport( pgconn,rec ) + + # make a excel file under /var/www/docbase/(@username)/(@projectno)/ + + #file_path = filename.to_s.gsub(/wrote excel file on /,"") + #puts "=========> file_path = #{file_path}" + pgconn.disconnect + filename = doc.outfile + file_path = doc.outpath + puts "=========> file_path = #{file_path}, filename = #{filename}" + + return file_path + + end + +#==================================== +# save / upload +#==================================== + + def s3Uploader data_dir, filepath, filename + + bucket = s3_bucket().freeze + region = s3_region().freeze + access_key = s3_key().freeze + secret_key = s3_Skey().freeze + + aws_storage = S3_StorageUtil.new( access_key,secret_key,region,bucket,data_dir ) + aws_bucket = S3_FolderUtil.new( "offlineRecog/work",aws_storage ) + + originPath = filepath + destPath = data_dir + filename = filename + + aws_bucket.uploadFile( originPath,destPath,filename ) + + aws_url = s3_domain() + '/' + data_dir + '/' + filename + + return aws_url + + end + + def photoSaver zekken_number, event_code, response + + commonbase = set_commonbase() + '/' + event_code + commonbase2 = set_commonbase2() + '/' + event_code + + docpath = commonbase + '/' + zekken_number + docpath2 = commonbase2 + '/' + zekken_number + + if( !Dir.exist?(docpath) )then + if( Dir.mkdir( docpath,0755 ) == 0 ) then + #p "mkdir #{commonbase}" + end + end + + filename = DateTime.now.to_s.gsub(':','-').gsub('+','_') + '.png' + + fullpath = docpath + '/' + filename + fullpath2 = docpath2 + '/' + filename + + open(fullpath, 'w') do |pass| + pass.write(response.body) + end + + fullpath2 = s3Uploader("#{event_code}/#{zekken_number}",docpath,filename) + + filenameTh = filename.gsub(".png","_th.png") + + imageOri = Magick::Image.read(fullpath).first + imageTh = imageOri.scale(image_size_width(), image_size_height()) + imageTh.write("temp/#{filenameTh}") + + nextpath = docpath + '/' + filenameTh + + FileUtils.mv("/var/www/temp/#{filenameTh}",nextpath) + # File.delete(fullpath) + + return fullpath2 + + end + + def chatLogger userId, talker, type, detail + + p "#{talker} : #{detail}" + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'chat_log' ) + + title = ["userid","talker","message_type","message_detail","create_at"] + record = {"userid" => userId, "talker" => talker, "message_type" => type, "message_detail" => detail, "create_at" => DateTime.now} + + sql = anytable.makeInsertKeySet(title,record) + begin + ret = anytable.exec(sql) # true or false + rescue => error + p error + end + + @pgconn.disconnect + + return "OK" + + end + + end + + def self.registered( app ) + app.helpers MobServer_gifuroge::Helpers + + app.get "/test_gifuroge" do + crossdomain + headjson + result = "git push test from development to production3" + p result + end + + + def calculateMonthlyScore(zekken_number, event_code) + @pgconn = UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost", "mobilous", 0, dbname) + anytable = UserPostgresTable.new + anytable.useTable(@pgconn, 'gps_information') + + # 現在の月の開始日と終了日を取得 + today = Date.today + start_date = today.beginning_of_month + end_date = today.end_of_month + + # 一ヶ月分のデータを取得 + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}' " \ + "AND create_at >= '#{start_date}' AND create_at <= '#{end_date}' " \ + "ORDER BY create_at ASC" + records = anytable.find2(where) + + @pgconn.disconnect + + # 日ごとにグループ化して得点を計算 + daily_scores = {} + (start_date..end_date).each do |date| + daily_records = records.select { |r| Date.parse(r['create_at']) == date } + + start_index = daily_records.index { |r| r['cp_number'] == -2 } + end_index = daily_records.index { |r| r['cp_number'] == -1 } + + if start_index && end_index && start_index < end_index + valid_records = daily_records[start_index+1...end_index] + score = valid_records.sum { |r| r['photo_point'].to_i } + daily_scores[date] = score + else + daily_scores[date] = 0 + end + end + + # 月間の合計得点を計算 + total_monthly_score = daily_scores.values.sum + + return { + daily_scores: daily_scores, + total_monthly_score: total_monthly_score + } + end + + +#==================================== +# LINEbot本体 +#==================================== + + app.post '/callback_gifuroge' do + crossdomain + # p "call back!" + body = request.body.read + # p "body read!" + signature = request.env['HTTP_X_LINE_SIGNATURE'] + # p "signature read!" + unless client.validate_signature(body, signature) + p "400 Bad Request" + error 400 do 'Bad Request' end + end + # p "not 400!" + events = client.parse_events_from(body) + # p "event read!" + events.each do |event| + userId = event['source']['userId'] + userdata = getUserName(userId) + if userdata["user_name"] == "get name error" then + message = { + type: 'text', + text: "エラーコード:USR-001\nユーザー名の取得に失敗しました。\n※このエラーが何度も発生する場合、エラーコードとゼッケン番号を添えて、運営に問い合わせて下さい。" + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', "エラーコード:USR-001\nユーザー名の取得に失敗しました。\n※このエラーが何度も発生する場合、エラーコードとゼッケン番号を添えて、運営に問い合わせて下さい。") + return "200 OK" + end + zekken_number = userdata["zekken_number"] + event_code = userdata["event_code"] + p "username : #{userdata["user_name"]} ( #{zekken_number} ( #{event_code} ) )" + case event + when Line::Bot::Event::Message + notZekken = false + status = checkStatus(userId) + + if zekken_number == "" then + status = checkStatus(userId) + if status['status'] != "zekkenAuthorization" then + notZekken = true + end + end + + agentF = false + agent_id = "" + if zekken_number != nil then + if (zekken_number.start_with?('a')) then + agent_id = zekken_number + zekken_number = getZekkenNumberByAgentId(zekken_number) + agentF = true + if status['status'] == "Goal" then + result = removeStatus(userId) + if result == "delete error" then + for i in 1..10 do + result = removeStatus(userId) + if result == "200 OK" then + break + end + end + end + status['status'] = "nothing" + + if result == "delete error" + message = { + type: 'text', + text: text_importantError("STA-002") + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_importantError("STA-002")) + return "200 OK" + end + end + end + end + + case event.type + when Line::Bot::Event::MessageType::Text + chatLogger(userId, 'user', 'text', event.message['text']) + + command = NKF.nkf('-w -Z4', NKF.nkf('--katakana -w', event.message['text'])).upcase # この一行により入力された内容は全て半角かつ、ひらがなはカタカナに、小文字アルファベットは大文字に、変換される + if status['status'] == "Goal" then + if command.to_s.start_with?('AGENT') then + commandAr = event.message['text'].split(' ') + + agent_id = agentAuthorization(commandAr[1]) + + if (agent_id == "ERROR") then + message = { + type: 'text', + text: text_notAgent() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_notAgent()) + return "200 OK" + else + end + + result = removeStatus(userId) + if result == "delete error" then + for i in 1..10 do + result = removeStatus(userId) + if result == "200 OK" then + break + end + end + end + + if result == "delete error" + message = { + type: 'text', + text: text_importantError("STA-002") + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_importantError("STA-002")) + return "200 OK" + end + agentRegister(userId,event.message['text'].to_s,client,event) + elsif (command == 'ログアウト' || command == 'LOGOUT') then + result = addUserData(userId, "", "") + if result == "UPDATE ERROR" then + message = { + type: 'text', + text: "エラーコード:USR-003\nログアウトの処理に失敗しました。\n恐れ入りますが、時間をあけてもう一度やり直して下さい。\n※このエラーが何度も発生する場合、LINEのユーザー名とエラーコードを運営に問い合わせて下さい。" + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', "エラーコード:USR-003\nログアウトの処理に失敗しました。\n恐れ入りますが、時間をあけてもう一度やり直して下さい。\n※このエラーが何度も発生する場合、LINEのユーザー名とエラーコードを運営に問い合わせて下さい。") + return "200 OK" + end + result = removeStatus(userId) + if result == "delete error" then + for i in 1..10 do + result = removeStatus(userId) + if result == "200 OK" then + break + end + end + end + + if result == "delete error" + message = { + type: 'text', + text: text_importantError("STA-002") + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_importantError("STA-002")) + return "200 OK" + end + message = { + type: 'text', + text: text_loguotSuccess() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_loguotSuccess()) + return "200 OK" + elsif (command.start_with?('ゼッケン番号:')) then + result = removeStatus(userId) + if result == "delete error" then + for i in 1..10 do + result = removeStatus(userId) + if result == "200 OK" then + break + end + end + end + + if result == "delete error" + message = { + type: 'text', + text: text_importantError("STA-002") + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_importantError("STA-002")) + return "200 OK" + end + + zekkenNumberRegister(userId, command.to_s, event_code, 8, client,event) + elsif (command.to_s.start_with?('ゼッケン:')) then + result = removeStatus(userId) + if result == "delete error" then + for i in 1..10 do + result = removeStatus(userId) + if result == "200 OK" then + break + end + end + end + + if result == "delete error" + message = { + type: 'text', + text: text_importantError("STA-002") + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_importantError("STA-002")) + return "200 OK" + end + + zekkenNumberRegister(userId, command.to_s, event_code, 6, client,event) + elsif (command.to_s.start_with?('TIMECH')) then + if (agentF) then + timeChRegister(userId, zekken_number, event_code, command, client, event) + end + elsif (command.to_s.start_with?('時間変更')) then + if (agentF) then + timeChRegister(userId, zekken_number, command, client, event) + end + elsif (command.to_s.start_with?('REPRINT')) then + if (agentF) then + reprinter(userId, zekken_number, event_code, client, event) + end + elsif (command.to_s.start_with?('再印刷')) then + if (agentF) then + reprinter(userId, zekken_number, event_code, client, event) + end + elsif (command.to_s.start_with?('LIST')) then + if (agentF) then + listUpper(userId, zekken_number, event_code, client, event) + end + elsif (command.to_s.start_with?('一覧')) then + if (agentF) then + listUpper(userId, zekken_number, event_code, client, event) + end + else + message = { + type: 'text', + text: text_alreadyGoal() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_alreadyGoal()) + return "200 OK" + end + end + + if notZekken then + if (command.start_with?('ゼッケン番号:')) then + zekkenNumberRegister(userId, command.to_s, event_code, 8, client,event) + elsif (command.to_s.start_with?('ゼッケン:')) then + zekkenNumberRegister(userId, command.to_s, event_code, 6, client,event) + elsif (command.to_s.start_with?('AGENT')) then + agentRegister(userId,event.message['text'].to_s,client,event) + return "200 OK" + elsif (command.to_s.start_with?('代理人')) then + agentRegister(userId,event.message['text'].to_s,client,event) + return "200 OK" + elsif (command.to_s.start_with?('CHECKIN')) then + if (agentF) then + checkinRegister(userId,command.to_s,agent_id,event_code,client,event) + end + elsif (command.to_s.start_with?('代理ログイン')) then + if (agentF) then + checkinRegister(userId,command.to_s,agent_id,event_code,client,event) + end + elsif (command.to_s.start_with?('CHECKOUT')) then + if (agentF) then + checkoutRegister(userId,agent_id,event_code,client,event) + end + elsif (command.to_s.start_with?('代理ログアウト')) then + if (agentF) then + checkoutRegister(userId,agent_id,event_code,client,event) + end + else + message = { + type: 'text', + text: text_noZekken1(userdata["user_name"]) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_noZekken1(userdata["user_name"])) + message = { + type: 'text', + text: text_noZekken2() + } + client.push_message(userId, message) + chatLogger(userId, 'bot', 'text', text_noZekken2()) + message = { + type: 'text', + text: text_noZekken3() + } + client.push_message(userId, message) + chatLogger(userId, 'bot', 'text', text_noZekken3()) + return "200 OK" + end + end + + case status['status'] + when 'nothing' + if (command.start_with?('ゼッケン番号:')) then + zekkenNumberRegister(userId, command.to_s, event_code, 8, client,event) + elsif (command.to_s.start_with?('ゼッケン:')) then + zekkenNumberRegister(userId, command.to_s, event_code, 6, client,event) + elsif (command.to_s.start_with?('CP番号:')) then + cpNumberRegister(userId, zekken_number, event_code, command.to_s, 5, client,event) + elsif (command.to_s.start_with?('CP:')) then + cpNumberRegister(userId, zekken_number, event_code, command.to_s, 3, client,event) + elsif (command.to_s.start_with?('ADD')) then + cp_number = command.split(' ')[1] + cpNumberRegister(userId, zekken_number, event_code, cp_number.to_s, 0, client,event) + elsif (command.to_s.start_with?('追加')) then + cp_number = command.split(' ')[1] + cpNumberRegister(userId, zekken_number, event_code, cp_number.to_s, 0, client,event) + elsif (command.to_s.start_with?('ゴール:') || command.to_s.start_with?('GOAL:')) then + goalRegister(userId,zekken_number, event_code, command.to_s, 5, client,event) + elsif (command.to_s.start_with?('ゴール ') || command.to_s.start_with?('GOAL ')) then + command = command.split(' ')[1] + goalRegister(userId,zekken_number, event_code, command.to_s, 0, client,event) + elsif (command.to_s.start_with?('ゴ:')) then + goalRegister(userId,zekken_number, event_code, command.to_s, 3, client,event) + elsif (command.to_s.start_with?('G:')) then + goalRegister(userId,zekken_number, event_code, command.to_s, 2, client,event) + elsif (command.to_s.start_with?('スタート')) then + startRegister(userId,zekken_number,client,event) + elsif (command.to_s.start_with?('START')) then + startRegister(userId,zekken_number,client,event) + elsif (command.to_s.start_with?('AGENT')) then + agentRegister(userId,event.message['text'].to_s,client,event) + elsif (command.to_s.start_with?('代理人')) then + agentRegister(userId,event.message['text'].to_s,client,event) + elsif (command.to_s.start_with?('CHECKIN')) then + if (agentF) then + checkinRegister(userId,command.to_s,agent_id,event_code,client,event) + end + elsif (command.to_s.start_with?('代理ログイン')) then + if (agentF) then + checkinRegister(userId,command.to_s,agent_id,event_code,client,event) + end + elsif (command.to_s.start_with?('CHECKOUT')) then + if (agentF) then + checkoutRegister(userId,agent_id,event_code,client,event) + end + elsif (command.to_s.start_with?('代理ログアウト')) then + if (agentF) then + checkoutRegister(userId,agent_id,event_code,client,event) + end + elsif (command.to_s.start_with?('INSERT')) then + if (agentF) then + insertTentativeRegister(userId, zekken_number,event_code, command, client, event) + end + elsif (command.to_s.start_with?('挿入')) then + if (agentF) then + insertTentativeRegister(userId, zekken_number, event_code, command, client, event) + end + elsif (command.to_s.start_with?('DELETE')) then + if (agentF) then + deleteRegister(userId, zekken_number, event_code, command, client, event) + end + elsif (command.to_s.start_with?('削除')) then + if (agentF) then + deleteRegister(userId, zekken_number, event_code, command, client, event) + end + elsif (command.to_s.start_with?('TIMECH')) then + if (agentF) then + timeChRegister(userId, zekken_number, event_code, command, client, event) + end + elsif (command.to_s.start_with?('時間変更')) then + if (agentF) then + timeChRegister(userId, zekken_number, event_code, command, client, event) + end + elsif (command.to_s.start_with?('REPRINT')) then + if (agentF) then + reprinter(userId, zekken_number, event_code, client, event) + end + elsif (command.to_s.start_with?('再印刷')) then + if (agentF) then + reprinter(userId, zekken_number, event_code, client, event) + end + elsif (command.to_s.start_with?('LIST')) then + if (agentF) then + listUpper(userId, zekken_number, event_code, client, event) + end + elsif (command.to_s.start_with?('一覧')) then + if (agentF) then + listUpper(userId, zekken_number, event_code, client, event) + end + elsif (command.to_s.start_with?('MOVE')) then + if (agentF) then + moveRegister(userId, zekken_number, event_code, command, client, event) + end + elsif (command.to_s.start_with?('移動')) then + if (agentF) then + moveRegister(userId, zekken_number, event_code, command, client, event) + end + elsif (command == 'ログアウト' || command == 'LOGOUT') then + result = addUserData(userId, "", "") + if result == "UPDATE ERROR" then + message = { + type: 'text', + text: "エラーコード:USR-003\nログアウトの処理に失敗しました。\n恐れ入りますが、時間をあけてもう一度やり直して下さい。\n※このエラーが何度も発生する場合、LINEのユーザー名とエラーコードを運営に問い合わせて下さい。" + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', "エラーコード:USR-003\nログアウトの処理に失敗しました。\n恐れ入りますが、時間をあけてもう一度やり直して下さい。\n※このエラーが何度も発生する場合、LINEのユーザー名とエラーコードを運営に問い合わせて下さい。") + return "200 OK" + end + message = { + type: 'text', + text: text_loguotSuccess() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_loguotSuccess()) + return "200 OK" + else # CP登録と仮定する + + if (command.to_s.start_with?('#')) then + command.delete_prefix!('#') + end + + cp_number = command.to_i + + if cp_number <= 0 then + return "200 OK" + end + + cpNumberRegister(userId, zekken_number, event_code, cp_number, 0, client,event) + + end + when "zekkenAuthorization" + if command.to_s.start_with?('PASSWORD:') then + password = event.message['text'].to_s.slice(0,9) + elsif command.to_s.start_with?('パスワード:') then + password = event.message['text'].to_s.slice(0,6) + elsif (command == 'NO' || command == "キャンセル" || command == "CANCEL" || command == "イイエ" || command == "ノー") then + result = removeStatus(userId) + if result == "delete error" then + + message = { + type: 'text', + text: "エラーコード:STA-002\nパスワード受付のキャンセルに失敗しました。\n恐れ入りますが、時間をあけてもう一度やり直して下さい。\n※このエラーが何度も発生する場合、LINEのユーザー名とエラーコードを運営に問い合わせて下さい。" + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', "エラーコード:STA-002\nパスワード受付のキャンセルに失敗しました。\n恐れ入りますが、時間をあけてもう一度やり直して下さい。\n※このエラーが何度も発生する場合、LINEのユーザー名とエラーコードを運営に問い合わせて下さい。") + return "200 OK" + + end + + message = { + type: 'text', + text: text_AuthorizationCancel() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_AuthorizationCancel()) + + return "200 OK" + + else + password = event.message['text'] + end + result = zekkenAuthorization(status['memory'], password) + if result["result"] == "OK" + + if getUserIdByZekkenNumber(result['zekken_number'],result["event_code"]) != "no zekken number" then + message = { + type: 'text', + text: text_alreadyZekken() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_alreadyZekken()) + + return "200 OK" + end + + result2 = addUserData(userId,result['zekken_number'],result["event_code"]) + if result2 == "UPDATE ERROR" then + message = { + type: 'text', + text: "エラーコード:USR-002\nログインには成功しましたが、チーム情報の紐付けに失敗しました。\n恐れ入りますが、時間をあけて再度パスワードを御入力頂けますでしょうか。\n※このエラーが何度も発生する場合、エラーコード、LINEのユーザー名を添えて、運営に問い合わせて下さい。" + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', "エラーコード:USR-002\nログインには成功しましたが、チーム情報の紐付けに失敗しました。\n恐れ入りますが、時間をあけて再度パスワードを御入力頂けますでしょうか。\n※このエラーが何度も発生する場合、エラーコード、LINEのユーザー名を添えて、運営に問い合わせて下さい。") + return "200 OK" + end + + result3 = removeStatus(userId) + if result3 == "delete error" then + for i in 1..10 do + result3 = removeStatus(userId) + if result3 == "200 OK" then + break + end + end + end + + if result3 == "delete error" + message = { + type: 'text', + text: text_importantError("STA-002") + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_importantError("STA-002")) + return "200 OK" + end + + message = { + type: 'text', + text: text_teamRegister(userdata["user_name"], result['team_name']) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_teamRegister(userdata["user_name"], result['team_name'])) + + + elsif result["result"] == "ERROR" + message = { + type: 'text', + text: text_passwordError() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_passwordError()) + + end + + when "cp_stanby" + + if (command == 'NO' || command == "キャンセル" || command == "イイエ" || command == "ノー") then + result = removeStatus(userId) + if result == "delete error" then + + message = { + type: 'text', + text: "エラーコード:STA-003\n写真受付のキャンセルに失敗しました。\n恐れ入りますが、時間をあけてもう一度やり直して下さい。\n※このエラーが何度も発生する場合、ゼッケン番号とエラーコードを運営に問い合わせて下さい。" + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', "エラーコード:STA-003\n写真受付のキャンセルに失敗しました。\n恐れ入りますが、時間をあけてもう一度やり直して下さい。\n※このエラーが何度も発生する場合、ゼッケン番号とエラーコードを運営に問い合わせて下さい。") + return "200 OK" + + end + + message = { + type: 'text', + text: text_AuthorizationCancel() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_AuthorizationCancel()) + + return "200 OK" + end + + when "goal_stanby" + + if (command == 'NO' || command == "キャンセル" || command == "イイエ" || command == "ノー") then + result = removeStatus(userId) + if result == "delete error" then + + message = { + type: 'text', + text: "エラーコード:STA-003\n写真受付のキャンセルに失敗しました。\n恐れ入りますが、時間をあけてもう一度やり直して下さい。\n※このエラーが何度も発生する場合、ゼッケン番号とエラーコードを運営に問い合わせて下さい。" + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', "エラーコード:STA-003\n写真受付のキャンセルに失敗しました。\n恐れ入りますが、時間をあけてもう一度やり直して下さい。\n※このエラーが何度も発生する場合、ゼッケン番号とエラーコードを運営に問い合わせて下さい。") + return "200 OK" + + end + + message = { + type: 'text', + text: text_AuthorizationCancel() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_AuthorizationCancel()) + + return "200 OK" + end + + when "insert" + + if (command == 'NO' || command == "キャンセル" || command == "イイエ" || command == "ノー") then + result = removeStatus(userId) + if result == "delete error" then + + message = { + type: 'text', + text: "エラーコード:STA-003\n写真受付のキャンセルに失敗しました。\n恐れ入りますが、時間をあけてもう一度やり直して下さい。\n※このエラーが何度も発生する場合、ゼッケン番号とエラーコードを運営に問い合わせて下さい。" + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', "エラーコード:STA-003\n写真受付のキャンセルに失敗しました。\n恐れ入りますが、時間をあけてもう一度やり直して下さい。\n※このエラーが何度も発生する場合、ゼッケン番号とエラーコードを運営に問い合わせて下さい。") + return "200 OK" + + end + + message = { + type: 'text', + text: text_AuthorizationCancel() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_AuthorizationCancel()) + + return "200 OK" + end + + when "start" + + if (command == 'NO' || command == "キャンセル" || command == "イイエ" || command == "ノー") then + result = removeStatus(userId) + if result == "delete error" then + + message = { + type: 'text', + text: "エラーコード:STA-003\nスタートのキャンセルに失敗しました。\n恐れ入りますが、時間をあけてもう一度やり直して下さい。\n※このエラーが何度も発生する場合、ゼッケン番号とエラーコードを運営に問い合わせて下さい。" + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', "エラーコード:STA-003\nスタートのキャンセルに失敗しました。\n恐れ入りますが、時間をあけてもう一度やり直して下さい。\n※このエラーが何度も発生する場合、ゼッケン番号とエラーコードを運営に問い合わせて下さい。") + return "200 OK" + + end + + message = { + type: 'text', + text: text_AuthorizationCancel() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_AuthorizationCancel()) + + return "200 OK" + + elsif (command == 'YES' || command == 'ハイ' || command == 'イエス') then + + removeAllGI(zekken_number, event_code) + + inputCPnumber(zekken_number,event_code,-2,set_originbase() + '/start.png') + + result = removeStatus(userId) + if result == "delete error" then + for i in 1..10 do + result = removeStatus(userId) + if result == "200 OK" then + break + end + end + end + + if result == "delete error" + message = { + type: 'text', + text: text_importantError("STA-002") + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_importantError("STA-002")) + return "200 OK" + end + + message = { + type: 'text', + text: text_startRun() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_startRun()) + return "200 OK" + + end + + end + when Line::Bot::Event::MessageType::Image + if notZekken then + chatLogger(userId, 'user', 'image', '[保存しなかった画像ファイル]') + message = { + type: 'text', + text: text_noZekken1(userdata["user_name"]) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_noZekken1(userdata["user_name"])) + message = { + type: 'text', + text: text_noZekken2() + } + client.push_message(userId, message) + chatLogger(userId, 'bot', 'text', text_noZekken2()) + message = { + type: 'text', + text: text_noZekken3() + } + client.push_message(userId, message) + chatLogger(userId, 'bot', 'text', text_noZekken3()) + return "200 OK" + end + + case status['status'] + when 'nothing' + chatLogger(userId, 'user', 'image', '[保存しなかった画像ファイル]') + # 何もなし + when 'cp_stanby' + + response = client.get_message_content(event.message['id']) + + fullpath = photoSaver(zekken_number, event_code, response) + + chatLogger(userId, 'user', 'image', fullpath) + + ### + #早野修正分 + #ユーザーのbuy_pointレコードが1なら追加の写真を要求する。 + #validation(重複チェック)などはいるか? + inputCPnumber(zekken_number, event_code, status['memory'], fullpath) + + if checkBuypointSingleRecord(zekken_number, event_code, status['memory']) + message = { + type: 'text', + text: text_ask_for_receipt_image(status['memory']) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_ask_for_receipt_image(status['memory'])) + return "200 OK" + end + ### + + + result = removeStatus(userId) + if result == "delete error" then + for i in 1..10 do + result = removeStatus(userId) + if result == "200 OK" then + break + end + end + end + + if result == "delete error" + message = { + type: 'text', + text: text_importantError("STA-002") + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_importantError("STA-002")) + return "200 OK" + end + + cp_name = getCPname(status['memory'], event_code) + cp_number = status['memory'].to_i + + + message = { + type: 'text', + text: text_registreCP(cp_number,cp_name) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_registreCP(cp_number,cp_name)) + + when 'goal_stanby' + + response = client.get_message_content(event.message['id']) + + fullpath = photoSaver(zekken_number, event_code, response) + + chatLogger(userId, 'user', 'image', fullpath) + + jdata = status['memory'] + data = JSON.parse(jdata) + + inputGoalTime(zekken_number,event_code,data['goal_time'],data['late_point'],fullpath) + + result = removeStatus(userId) + if result == "delete error" then + for i in 1..10 do + result = removeStatus(userId) + if result == "200 OK" then + break + end + end + end + + if result == "delete error" + message = { + type: 'text', + text: text_importantError("STA-002") + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_importantError("STA-002")) + return "200 OK" + end + + message = { + type: 'text', + text: text_getGoalPhoto() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_getGoalPhoto()) + + inputStatus(userId, "Goal", 'nil') + + Thread.new do + makeScoreboardThread(zekken_number, event_code) + end + return "200 OK" + + when "insert" + + response = client.get_message_content(event.message['id']) + + fullpath = photoSaver(zekken_number, event_code, response) + + chatLogger(userId, 'user', 'image', fullpath) + + insertRegister(userId, zekken_number, event_code, status['memory'], fullpath, client, event) + + end + when Line::Bot::Event::MessageType::Location + latitude = event.message['latitude'] + longitude = event.message['longitude'] + + chatLogger(userId, 'user', 'location', "latitude : #{latitude} , longitude : #{longitude}") + + if notZekken then + message = { + type: 'text', + text: text_noZekken1(userdata["user_name"]) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_noZekken1(userdata["user_name"])) + message = { + type: 'text', + text: text_noZekken2() + } + client.push_message(userId, message) + chatLogger(userId, 'bot', 'text', text_noZekken2()) + message = { + type: 'text', + text: text_noZekken3() + } + client.push_message(userId, message) + chatLogger(userId, 'bot', 'text', text_noZekken3()) + return "200 OK" + end + + case status['status'] + when 'nothing' + + p "latitude : #{latitude} , longitude : #{longitude}" + cp_data = getCPnameByThreshols(latitude,longitude, event_code) + + if cp_data["result"] == "no cp error" then + message = { + type: 'text', + text: text_noLocation() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_noLocation()) + return "200 OK" + end + + if (cp_data["cp_number"].to_i == -1) then + message = { + type: 'text', + text: text_goalCheck1() + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_goalCheck1()) + message = { + type: 'text', + text: text_goalCheck2() + } + client.push_message(userId, message) + chatLogger(userId, 'bot', 'text', text_goalCheck2()) + message = { + type: 'text', + text: text_goalCheck3() + } + client.push_message(userId, message) + chatLogger(userId, 'bot', 'text', text_goalCheck3()) + return "200 OK" + end + + if cpDoubleCheck(zekken_number, event_code, cp_data['cp_number']) then + message = { + type: 'text', + text: text_registredCP(cp_data["cp_number"],cp_data["cp_name"]) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_registredCP(cp_data["cp_number"],cp_data["cp_name"])) + return "200 OK" + end + + if cp_data['buy_point'] != '0' then + inputStatus(userId,'cp_stanby',cp_data["cp_number"]) + + message = { + type: 'text', + text: text_standByBuyPoint(cp_data["cp_number"],cp_data["cp_name"]) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_standByBuyPoint(cp_data["cp_number"],cp_data["cp_name"])) + return "200 OK" + end + + fullpath = set_originbase() + '/location_checked.png' + + inputCPnumber(zekken_number,event_code,cp_data["cp_number"],fullpath) + + cp_number = cp_data["cp_number"] + + message = { + type: 'text', + text: text_registreCP(cp_number,cp_data["cp_name"]) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_registreCP(cp_number,cp_data["cp_name"])) + return "200 OK" + + when 'cp_stanby' + p "latitude : #{latitude} , longitude : #{longitude}" + cp_data = {} + if status['memory'].to_i == 998 then + cp_data["cp_number"] = 998 + cp_data["cp_name"] = "テストチェックポイント2" + cp_data["buy_point"] = '0' + else + cp_data = getCPnameByThreshols(latitude,longitude,event_code,status['memory']) + end + + if cp_data["result"] == "no cp error" then + cp_name = getCPname(status["memory"],event_code) + if status["memory"].to_i < 996 then + cp_number = getPhotoPointByCPNum(status["memory"],event_code) + else + cp_number = status["memory"] + end + message = { + type: 'text', + text: text_noLocationCSB(cp_number,cp_name) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_noLocationCSB(cp_number,cp_name)) + return "200 OK" + end + + if cp_data['buy_point'] != '0' then + message = { + type: 'text', + text: text_BuyPointError(cp_data["cp_number"],cp_data["cp_name"]) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_BuyPointError(cp_data["cp_number"],cp_data["cp_name"])) + return "200 OK" + end + + fullpath = set_originbase() + '/location_checked.png' + + inputCPnumber(zekken_number,event_code,cp_data["cp_number"],fullpath) + + if status["memory"].to_i < 996 then + cp_number = getPhotoPointByCPNum(status["memory"],event_code) + else + cp_number = status["memory"] + end + + message = { + type: 'text', + text: text_registreCP(cp_number,cp_data["cp_name"]) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_registreCP(cp_number,cp_data["cp_name"])) + + result = removeStatus(userId) + if result == "delete error" then + for i in 1..10 do + result = removeStatus(userId) + if result == "200 OK" then + break + end + end + end + + if result == "delete error" + message = { + type: 'text', + text: text_importantError("STA-002") + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_importantError("STA-002")) + return "200 OK" + end + + return "200 OK" + + end + + when Line::Bot::Event::MessageType::File + if notZekken then + chatLogger(userId, 'user', 'file', "[保存しなかったファイル]") + message = { + type: 'text', + text: text_noZekken1(userdata["user_name"]) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_noZekken1(userdata["user_name"])) + message = { + type: 'text', + text: text_noZekken2() + } + client.push_message(userId, message) + chatLogger(userId, 'bot', 'text', text_noZekken2()) + message = { + type: 'text', + text: text_noZekken3() + } + client.push_message(userId, message) + chatLogger(userId, 'bot', 'text', text_noZekken3()) + return "200 OK" + end + chatLogger(userId, 'user', 'file', "[保存しなかったファイル]") + + # commonbase = set_commonbase() + # docpath = commonbase + '/' + event_code + '/' + zekken_number + # filename = DateTime.now.to_s.gsub(':','-').gsub('+','_') + '.xml' + # fullpath = docpath + '/' + filename + # + # response = client.get_message_content(event.message['id']) + # + # open(fullpath, 'w') do |pass| + # pass.write(response.body) + # end + # + # chatLogger(userId, 'user', 'file', fullpath) + # + # doc = REXML::Document.new(File.open(fullpath)) + # + # doc.elements.each('gpx/trk/trkseg/trkpt') do |elm| + # + # lat = elm.attribute('lat').value + # lon = elm.attribute('lon').value + # + # p "lat : #{lat}, lon : #{lon}" + # + # inputGPSlog(zekken_number,event_code,lat,lon) + # + # end + + message = { + type: 'text', + text: text_getGPSlogger() + } + client.reply_message(event['replyToken'], message) + else + chatLogger(userId, 'user', 'other', "[テキスト、画像、位置情報、ファイル以外の保存しなかった何か]") + if notZekken then + message = { + type: 'text', + text: text_noZekken1(userdata["user_name"]) + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', text_noZekken1(userdata["user_name"])) + message = { + type: 'text', + text: text_noZekken2() + } + client.push_message(userId, message) + chatLogger(userId, 'bot', 'text', text_noZekken2()) + message = { + type: 'text', + text: text_noZekken3() + } + client.push_message(userId, message) + chatLogger(userId, 'bot', 'text', text_noZekken3()) + return "200 OK" + end + end + end + end + p "200 OK" + end + + # https://natnats.mobilous.com/get_zekken_list?event='ogaki' + + app.get "/get_zekken_list" do + crossdomain + headjson + + p "/get_zekken_list" + p "params : #{params}" + + return JSON.generate(getZekkenListByTT(params['event'])) + + end + + # https://natnats.mobilous.com/get_photo_list?zekken=[zekken_number]&pw=[password] + + app.get "/get_photo_list" do + crossdomain + + p "/get_photo_list" + + zekken = params['zekken'] + password = params['pw'] + event_code = params['event'] + + result = zekkenAuthorization(zekken,password) + + if result["zekken_number"] == "ERROR" || result["event_code"] != event_code then + headjson + return JSON.generate({"status" => "ERROR"}) + end + # ゼッケン番号の変換。美濃加茂ロゲで、以下のゼッケン番号の登録を間違えていたので急造の変換 + zekken_conversion = { + "MF3-160" => "MZ3-160", + "MF3-161" => "MZ3-161", + "MF3-162" => "MZ3-162", + "MF3-163" => "MZ3-163", + "MF5-170" => "MZ5-170", + "MF5-171" => "MZ5-171", + "MF5-172" => "MZ5-172", + "MF5-173" => "MZ5-173", + "MF5-174" => "MZ5-174", + "MF5-175" => "MZ5-175", + "MF5-176" => "MZ5-176", + "MF5-177" => "MZ5-177", + "MF5-178" => "MZ5-178", + "MF5-179" => "MZ5-179" + } + + if zekken_conversion.key?(zekken) + zekken = zekken_conversion[zekken] + end + + photo_list = [] + + routePath = "#{set_commonbase()}/route_photo/#{zekken}.png" + routePath2 = "#{set_commonbase2()}/route_photo/#{zekken}.png" + + if File.exist?(routePath) then + photo_list.push(routePath2) + end + photo_list.concat(getPhotoList(zekken, event_code)) + + headjson + return JSON.generate({"status" => "OK", "photo_list" => photo_list, "report" => getFinalReport(zekken,event_code)}) + + end + + # https://natnats.mobilous.com/getScoreboard?z_num=[zekken_number] + + app.get "/getScoreboard" do + crossdomain + + p "/getScoreboard" + p "params : #{params}" + + zekken_number = params["z_num"] + event_code = params["event"] + + file_path = getScoreboardOgaki(zekken_number,event_code) + + content_type "application/xlsx" + attachment "#{file_path}" + + send_file(file_path, :filename => "#{zekken_number}_scoreboardOgaki.xlsx",:type => "application/xlsx", :disposition => 'attachment') + + end + + # app.post "/xlsx_receive_ogaki" do + # crossdomain + # + # savepath = set_commonbase() + "/temp/#{params['input_file'][:filename]}" + # + # if (Dir.exist?(savepath) ) then + # File.delete(savepath) + # end + # + # File.open(savepath, 'wb') do |f| + # f.write params['input_file'][:tempfile].read + # end + # + # @pgconn=UserPostgres.new + # dbname = set_dbname() + # @pgconn.connectPg("localhost","mobilous",0,dbname) + # + # template = AppExeExcelWorkBook.new + # template.readWorkBook(savepath) + # + # dataSheet = AppExeExcelWorkSheet.new + # dataSheet.initLoad(template,"計算用") + # + # if dataSheet.getCell(1,2).value == nil then + # return "no zekken error" + # end + # + # zekken_number = dataSheet.getCell(1,2).value + # + # anytable=UserPostgresTable.new + # anytable.useTable( @pgconn,'user_table' ) + # anytable2=UserPostgresTable.new + # anytable2.useTable( @pgconn,'gps_information' ) + # + # userId = getUserIdByZekkenNumber(zekken_number) + # + # if userId == "no zekken number" then + # + # title = ["userid", "zekken_number", "create_at", "update_at"] + # + # record = {"userid" => zekken_number, "zekken_number" => zekken_number, "create_at" => DateTime.now, "update_at" => DateTime.now} + # + # sql = anytable.makeInsertKeySet(title,record) + # p sql + # + # begin + # ret = anytable.exec(sql) # true or false + # rescue => error + # p error + # end + # + # userId = zekken_number + # + # end + # + # + # title = ["user_name", "cp_number", "create_at", "update_at"] + # + # col = 1 + # line = 6 + # + # for i in 0 .. 99 do + # if dataSheet.getCell(line,col) == nil then + # break + # end + # if dataSheet.getCell(line,col).value == nil then + # break + # end + # rec = dataSheet.getCell(line,col).value + # if (cpDoubleCheck(zekken_number,rec)) then + # p "double! #{rec}" + # else + # record = {"user_name" => userId, "cp_number" => rec, "create_at" => DateTime.now, "update_at" => DateTime.now} + # sql = anytable2.makeInsertKeySet(title,record) + # p sql + # + # begin + # ret = anytable2.exec(sql) # true or false + # rescue => error + # p error + # end + # end + # + # col += 1 + # + # if col == 11 then + # col = 1 + # line += 5 + # end + # if line == 56 then + # break + # end + # end + # + # goal_time = dataSheet.getCell(3,8).value + # + # late_point = dataSheet.getCell(56,3).value + # + # title = ["user_name", "goal_time", "late_point", "create_at", "update_at"] + # + # record = {"user_name" => userId, "goal_time" => goal_time, "late_point" => late_point, "create_at" => DateTime.now, "update_at" => DateTime.now} + # sql = anytable2.makeInsertKeySet(title,record) + # p sql + # + # begin + # ret = anytable2.exec(sql) # true or false + # rescue => error + # p error + # end + # + # @pgconn.disconnect + # + # p "200 OK" + # + # end + +#==================================== +# realtimemonitor API +#==================================== + + app.get "/realtimeMonitor" do + crossdomain + + p "/realtimeMonitor" + p "params : #{params}" + + event_code = params["event_code"] + class_name = params["class"] + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'realtimemonitor' ) + + where = "event_code = '#{event_code}'" + + if class_name == nil || class_name == "" then + else + where = where + "AND class_name = '#{class_name}'" + end + + list = anytable.find2(where) + result = [] + + list.each { |rec| + result.push(rec) + } + + @pgconn.disconnect + + headjson + return JSON.generate(result) + + end + + app.get "/realtimeMonitor_zekken_narrow" do + crossdomain + + p "/realtimeMonitor_zekken_narrow" + p "params : #{params}" + + zekken_number = params["zekken"] + event_code = params["event_code"] + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'realtimemonitor' ) + + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + + list = anytable.find2(where) + result = [] + + list.each { |rec| + result.push(rec) + } + + @pgconn.disconnect + + headjson + return JSON.generate(result) + + end + + app.get "/getRoute" do + crossdomain + + p "/getRoute" + p "params : #{params}" + + team_name = params["team"] + event_code = params["event_code"] + + zekken_number = getZekkenNumberByTeamName(team_name,event_code) + p "zekken_number: #{zekken_number}" + + if zekken_number == "no zekken number" then + headjson + return JSON.generate({"status" => "ERROR"}) + end + + input_file = "#{set_commonbase}/#{event_code}/#{zekken_number}/waypoints.csv" + + bounds = get_lat_lng_bounds_for_event_code(event_code) + include_min_lat = bounds[:min_latitude] + include_max_lat = bounds[:max_latitude] + include_min_lng = bounds[:min_longitude] + include_max_lng = bounds[:max_longitude] + + #ファイルがあって + #if File.exist?(input_file) && event_code != '大垣2' + if File.exist?(input_file) + data = CSV.read(input_file) + if data.empty? + result = getDataFromDatabase(zekken_number, event_code) + else + result = [] + data.each do |line| + + latitude = line[0].to_f + longitude = line[1].to_f + + # 緯度経度が指定された範囲内にある場合のみ追加 + if (include_min_lat..include_max_lat).include?(latitude) && (include_min_lng..include_max_lng).include?(longitude) + waypoint = { + "latitude" => latitude.to_s, + "longitude" => longitude.to_s, + "create_at" => line[2] + } + result.push(waypoint) + end + end + #csvそのまま表示する時の処理。 + # else + # result = [] + # data.each do |line| + # waypoint = { + # "latitude" => line[0], + # "longitude" => line[1], + # "create_at" => line[2] + # } + # result.push(waypoint) + # end + end + else + result = getDataFromDatabase(zekken_number, event_code) + end + + # p "result: #{result}" + + result2 = {"status" => "OK"} + + result2["detail"] = result + + headjson + return JSON.generate(result2) + + end + + app.get "/fetchUserLocations" do + crossdomain + + p "/getRoute" + p "params : #{params}" + + zekken_number = params["zekken_number"] + event_code = params["event_code"] + + result = getDataFromDatabase(zekken_number, event_code) + + headjson + return JSON.generate(result) + + + end + + app.get "/generate_route_image" do + begin + crossdomain + headjson + + p "/generate_route_image" + p "params : #{params}" + + event_code = params["event_code"] + zekken_number = params["zekken_number"] + + # データの取得 + gps_data = getGpsList(zekken_number, event_code) + + p "GPS data: #{gps_data}" + + if gps_data.empty? + return JSON.generate({"status" => "ERROR", "detail" => "No GPS data found for this participant"}) + end + + # イベントの範囲を取得 + bounds = get_lat_lng_bounds_for_event_code(event_code) + + p "Bounds: #{bounds}" + + # 画像生成 + image = generate_route_image(gps_data, bounds) + + # 画像の保存 + filename = "route_#{event_code}_#{zekken_number}_#{Time.now.strftime("%Y%m%d%H%M%S")}.png" + save_path = "#{set_commonbase()}/#{event_code}/route_images/#{filename}" + + # ディレクトリが存在しない場合は作成 + FileUtils.mkdir_p(File.dirname(save_path)) + + image.write(save_path) + + # S3にアップロード + s3_url = s3Uploader("#{event_code}/route_images", File.dirname(save_path), filename) + + return JSON.generate({"status" => "OK", "image_url" => s3_url}) + rescue => e + puts "Error: #{e.message}" + puts e.backtrace.join("\n") + return JSON.generate({"status" => "ERROR", "detail" => e.message, "backtrace" => e.backtrace}) + end + end + + + +app.get "/getAllRoutes" do + crossdomain + + p "/getAllRoutes" + p "params : #{params}" + + event_code = params["event_code"] + class_name_param = params["class_name"] # class_name パラメータの取得 + class_name = class_name_param unless class_name_param.nil? || class_name_param.empty? || class_name_param == "全て" + + @pgconn = UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost", "mobilous", 0, dbname) + anytable = UserPostgresTable.new + anytable.useTable(@pgconn, 'gps_detail_for_animation') + + # class_name が指定されている場合は、それをクエリの条件に含める + class_condition = class_name ? "AND class_name = '#{class_name}'" : "" + + result = {} + zekken_list = anytable.find2("event_code = '#{event_code}' #{class_condition} ORDER BY zekken_number") + .map { |rec| rec["zekken_number"] }.uniq + + zekken_list.each do |zekken_number| + team_name = get_team_name(zekken_number, event_code) + input_file = "#{set_commonbase}/#{event_code}/#{zekken_number}/waypoints.csv" + route_data = [] + + if File.exist?(input_file) && event_code != '大垣2' + CSV.foreach(input_file) do |line| + waypoint = { + "latitude" => line[0], + "longitude" => line[1], + "create_at" => line[2], + "team_name" => team_name + # class_name はここでは不要なので追加しない + } + route_data << waypoint + end + else + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}' #{class_condition} ORDER BY serial_number" + list = anytable.find2(where) + list.each do |rec| + waypoint = rec.merge("team_name" => team_name) # ここでもclass_nameは不要 + route_data << waypoint + end + end + + result[zekken_number] = route_data + end + @pgconn.disconnect + result2 = {"status" => "OK", "detail" => result} + + headjson + return JSON.generate(result2) +end + + + + app.get "/getStartPoint" do + crossdomain + headjson + + p "getStartPoint" + p "params : #{params}" + + event_code = params['event'] + + result = getCPlatlngByCPnumber(-2, event_code) + + if result["status"] == "no cp error" then + return JSON.generate({"status" => "ERROR", "detail" => "no such cp"}) + end + + return JSON.generate(result) + end + + app.get "/get_ranking" do + crossdomain + + p "get_ranking" + p "params : #{params}" + + class_name = params["class"] + event_code = params["event"] + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'ranking_fix' ) + + where = "class_name = '#{class_name}' AND event_code ='#{event_code}' ORDER BY point DESC" + + list = anytable.find2(where) + result = [] + + list.each { |rec| + result.push(rec) + } + + @pgconn.disconnect + + headjson + return JSON.generate(result) + + end + + app.get "/all_ranking_top3" do + crossdomain + headjson + + p "/all_ranking_top3" + p "params : #{params}" + + event_code = params["event"] + + class_list = ['3時間一般','3時間ファミリー','3時間自転車','3時間ソロ男子','3時間ソロ女子','3時間パラロゲ','3時間無料','5時間一般','5時間ファミリー','5時間自転車','5時間ソロ男子','5時間ソロ女子'] + class_map = {'3時間一般'=>'一般-3時間','3時間ファミリー'=>'ファミリー-3時間','3時間自転車'=>'自転車-3時間','3時間ソロ男子'=>'ソロ男子-3時間','3時間ソロ女子'=>'ソロ女子-3時間','3時間パラロゲ'=>'パラロゲ-3時間','3時間無料'=>'お試し-3時間','5時間一般'=>'一般-5時間','5時間ファミリー'=>'ファミリー-5時間','5時間自転車'=>'自転車-5時間','5時間ソロ男子'=>'ソロ男子-5時間','5時間ソロ女子'=>'ソロ女子-5時間'} + + result_hash = {} + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","admin",0,dbname) + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'ranking_fix' ) + + class_list.each{ |class_name| + + alternative = class_map[class_name] + where = "(class_name = '#{class_name}' or class_name = '#{alternative}') AND event_code = '#{event_code}' ORDER BY point DESC" + + list = anytable.find2(where) + result = [] + + count = 0 + + list.each { |rec| + count += 1 + result.push(rec) + if count == 3 then + break + end + } + + result_hash[class_name] = result + + } + @pgconn.disconnect + return JSON.generate(result_hash) + + end + + app.get "/analyze_point" do + crossdomain + headjson + + p "/analyze_point" + p "params : #{params}" + + lat = params["lat"].to_f + lng = params["lng"].to_f + team_name = params["team_name"] + event_code = params["event_code"] + + zekken_number = getZekkenNumberByTeamName(team_name, event_code) + if zekken_number == "no zekken number" then + return JSON.generate({"status" => "ERROR", "detail" => "該当するチーム名が存在しません。the team name is not exist."}) + end + + gps_data = getGpsList(zekken_number, event_code) + + # 最も近い地点を見つける + closest_point = gps_data.min_by { |point| haversine_distance(lat, lng, point['latitude'].to_f, point['longitude'].to_f) } + + # 前後の点を含めた分析を行う + index = gps_data.index(closest_point) + prev_point = index > 0 ? gps_data[index - 1] : nil + next_point = index < gps_data.length - 1 ? gps_data[index + 1] : nil + + # 速度と移動タイプを計算 + speed, movement_type = calculate_speed_and_type(prev_point, closest_point, next_point) + + # 累積距離を計算 + cumulative_distance = calculate_cumulative_distance(gps_data, index) + + result = { + "status" => "OK", + "latitude" => closest_point['latitude'], + "longitude" => closest_point['longitude'], + "time" => closest_point['create_at'], + "speed" => speed, + "movement_type" => movement_type, + "cumulative_distance" => cumulative_distance + } + + JSON.generate(result) + end + + # app.get "/all_ranking_top3_for_fcgifu" do + # crossdomain + # headjson + + # p "/all_ranking_top3_for_fcgifu" + # p "params : #{params}" + + # result_hash = {} + # @pgconn = UserPostgres.new + # dbname = set_dbname() + # @pgconn.connectPg("localhost", "admin", 0, dbname) + + # begin + # # Get all unique event_codes + # event_code + # s = get_unique_event_codes(@pgconn) + + # event_codes.each do |event_code| + # # イベントコードごとに、クラス別の上位3チームを取得 + # top_users_by_class = get_top_users_by_class(@pgconn, event_code) + + # result_hash[event_code] = top_users_by_class + # end + + # @pgconn.disconnect + # return JSON.generate(result_hash) + # rescue StandardError => e + # @pgconn.disconnect if @pgconn + # return JSON.generate({ error: e.message, backtrace: e.backtrace }) + # end + # end + app.get "/all_ranking_for_fcgifu" do + crossdomain + headjson + + p "/all_ranking_for_fcgifu" + p "params : #{params}" + + result_hash = {} + @pgconn = UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost", "admin", 0, dbname) + + begin + # Get all unique event_codes + event_codes = get_unique_event_codes(@pgconn) + + event_codes.each do |event_code| + # イベントコードごとに、全ユーザーを取得 + all_users_by_class = get_all_users_by_class(@pgconn, event_code) + + # 各クラスの全ユーザーのルート情報を取得 + all_users_by_class.each do |class_name, users| + users.each do |user| + user["route"] = get_user_route(@pgconn, event_code, user["zekken_number"]) + end + end + + result_hash[event_code] = all_users_by_class + end + + @pgconn.disconnect + return JSON.generate(result_hash) + rescue StandardError => e + @pgconn.disconnect if @pgconn + return JSON.generate({ error: e.message, backtrace: e.backtrace }) + end + end + + app.get "/all_ranking_top3_for_fcgifu" do + crossdomain + headjson + + p "/all_ranking_top3_for_fcgifu" + p "params : #{params}" + + result_hash = {} + @pgconn = UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost", "admin", 0, dbname) + + begin + # Get all unique event_codes + event_codes = get_unique_event_codes(@pgconn) + + event_codes.each do |event_code| + # イベントコードごとに、クラス別の上位3チームを取得 + top_users_by_class = get_top_users_by_class(@pgconn, event_code) + + # 各クラスの上位ユーザーのルート情報を取得 + top_users_by_class.each do |class_name, users| + users.each do |user| + user["route"] = get_user_route(@pgconn, event_code, user["zekken_number"]) + end + end + + result_hash[event_code] = top_users_by_class + end + + @pgconn.disconnect + return JSON.generate(result_hash) + rescue StandardError => e + @pgconn.disconnect if @pgconn + return JSON.generate({ error: e.message, backtrace: e.backtrace }) + end + end + + ##移動経路出力 + + app.get "/top_users_routes" do + crossdomain + headjson + + event_code = params['event_code'] + class_name = params['class_name'] + + @pgconn = UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost", "mobilous", 0, dbname) + + routes = get_top_users_routes(@pgconn, event_code, class_name) + + bounds = get_lat_lng_bounds_for_event_code(event_code) + + processed_routes = {} + routes.each do |zekken_number, route_data| + processed_routes[zekken_number] = process_route_data(route_data, bounds) + end + + @pgconn.disconnect + + JSON.generate({ + status: "OK", + routes: processed_routes + }) + end + + + + +#==================================== +# rogaining simulator API +#==================================== + + app.get "/getCheckpointList" do + crossdomain + headjson + + p "/getCheckpointList" + p "params : #{params}" + + event_code = params['event'] + + return JSON.generate(getCheckpointList(event_code)) + + end + + app.get "/rogainingSimulator" do + crossdomain + headjson + + p "/rogainingSimulator" + p "params : #{params}" + + begin + event_code = params["event_code"].to_s + course_time = params["course_time"].to_i + pause_time_free = params["pause_time_free"].to_i + pause_time_paid = params["pause_time_paid"].to_i + spare_time = params["spare_time"].to_i + target_velocity = params["target_velocity"].to_f + p "target_velocity : #{target_velocity}" + rescue => e + p e + return JSON.generate({"status" => "error", "detail" => "Invalid arguments provided."}) + end + begin + free_node_to_visit = params["free_node_to_visit"].scan(/\d+/).map(&:to_i) + rescue => e + p e + free_node_to_visit = [] + end + begin + paid_node_to_visit = params["paid_node_to_visit"].scan(/\d+/).map(&:to_i) + rescue => e + p e + paid_node_to_visit = [] + end + simResult = rogainingSimulator(event_code, course_time, pause_time_free, pause_time_paid, spare_time, target_velocity, free_node_to_visit, paid_node_to_visit) + + if (simResult["status"] == "ERROR") then + return JSON.generate({"status" => "ERROR", "detail" => simResult["detail"]}) + end + + # return JSON.generate(simResult) # まずは仮に + + cp_list = simResult["detail"]["route"] + + if cp_list[1].to_i == 0 then + return JSON.generate({"status" => "ERROR", "detail" => "Could not find the optimal route."}) + end + + userId = getMaxUserNumByRSR(event_code).to_i + 1 + + cp_list.shift #頭の0を除去 + + response_cp_list = [] + + inputRogSimRecord(userId,event_code,-2) + + result = getCPlatlngByCPnumber(-2,event_code) + if result["status"] == "no cp error" then + return JSON.generate({"status" => "ERROR", "detail" => "no cp error"}) + end + response_cp_list.push("latitude" => result["record"]["latitude"], "longitude" => result["record"]["longitude"]) + + cp_list.each do |n| + if n.to_i == 0 then + inputRogSimRecord(userId,event_code,-1) + result = getCPlatlngByCPnumber(-1,event_code) + if result["status"] == "no cp error" then + return JSON.generate({"status" => "ERROR", "detail" => "no cp error"}) + end + response_cp_list.push("latitude" => result["record"]["latitude"], "longitude" => result["record"]["longitude"]) + else + inputRogSimRecord(userId,event_code,n.to_i) + result = getCPlatlngByCPnumber(n.to_i,event_code) + if result["status"] == "no cp error" then + return JSON.generate({"status" => "ERROR", "detail" => "no cp error"}) + end + response_cp_list.push("latitude" => result["record"]["latitude"], "longitude" => result["record"]["longitude"]) + end + end + + # return JSON.generate({"status" => "OK", "detail" => response_cp_list}) #仮2 + + begin + file_address = makeRogSimResultSheet(userId,event_code) + rescue => e + p e + return JSON.generate({"status" => "ERROR", "detail" => "Failed to generate the result data."}) + end + + if file_address == "no data error" then + return JSON.generate({"status" => "ERROR", "detail" => "Failed to generate the result data."}) + end + + return JSON.generate({"status" => "OK", "cp_list" => response_cp_list, "address" => file_address}) + + end + +#==================================== +# checkin admin API +#==================================== + + app.get "/getCheckinList" do + crossdomain + headjson + + p "/getCheckinList" + p "params : #{params}" + + zekken = params["zekken"] + event_code = params["event"] + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'gps_detail_fix' ) + + where = "zekken_number = '#{zekken}' AND event_code = '#{event_code}' ORDER BY serial_number" + + list = anytable.find2(where) + result = [] + + list.each { |rec| + result.push(rec) + } + + @pgconn.disconnect + + result2 = {} + + result2 = {"status" => "OK"} + + result2["detail"] = result + + return JSON.generate(result2) + + end + + # app.delete "/deleteCheckin" do + app.get "/deleteCheckin" do # deleteではCORSpolisyのエラーが出るため + crossdomain + headjson + + p "/deleteCheckin" + p "params : #{params}" + + zekken = params["zekken"] + event_code = params["event"] + sn = params["sn"] + + command = "DELETE #{sn}" + + result = deleteRegister('API', zekken, event_code, command, nil, nil, true) + + if result == "delete error" then + return JSON.generate({"status" => "error"}) + end + + return JSON.generate({"status" => "OK"}) + + end + + app.get "/moveCheckin" do # patchではCORSpolisyのエラーが出るため + crossdomain + headjson + + p "/moveCheckin" + p "params : #{params}" + + zekken = params["zekken"] + event_code = params["event"] + old_sn = params["old_sn"] + new_sn = params["new_sn"] + + command = "MOVE #{old_sn} #{new_sn}" + + result = moveRegister('API', zekken, event_code, command, nil, nil, true) + + if (checkAgentFlag(zekken, event_code) == false) then + + inputAgentFlag(zekken, event_code, 'checkinAdmin') + + end + + if result == 'OK' then + return JSON.generate({"status" => "OK"}) + end + + return JSON.generate({"status" => "error", "detail" => result}) + + end + + app.get "/startCheckin" do + crossdomain + headjson + + p "/startCheckin" + p "params : #{params}" + + event_code = params["event"] + zekken_number = params["zekken"] + + #FC岐阜コラボの時に、スタート時にチェックイン情報が全削除されないようにする + + # removeAllGI(zekken_number, event_code) + + inputCPnumber(zekken_number,event_code,-2,set_originbase() + '/start.png') + + #bonus_point_flagにデータがあったらポイント追加 + # if (checkBonusPointFlag(zekken_number, event_code) == true) then + # inputCPnumber(zekken_number,event_code,102,set_originbase() + '/start.png') + # end + + # if (checkAgentFlag(zekken_number, event_code) == false) then + # inputAgentFlag(zekken_number, event_code, agent_id) + # end + + return JSON.generate({"status" => "OK"}) + + end + + app.get "/addCheckin" do + crossdomain + headjson + + p "/addCheckin" + p "params : #{params}" + + event_code = params["event"] + zekken_number = params["zekken"] + checkin_list = params["list"] + + errorAr = [] + + checkinArr = checkin_list.split(',') + checkinArr.each { |cp_number| + if cp_number != "" then + if cp_number == "no cp error" then + errorAr.push(cp_number) + elsif cpDoubleCheck(zekken_number, event_code, cp_number) then + errorAr.push(cp_number) + elsif getCPname(cp_number, event_code) == "no cp error" then + errorAr.push(cp_number) + else + inputCPnumber(zekken_number,event_code,cp_number,set_originbase() + '/photo_none.png') + end + end + } + + if (checkAgentFlag(zekken_number, event_code) == false) then + inputAgentFlag(zekken_number, event_code, 'checkinAdmin') + end + + if errorAr == [] then + return JSON.generate({"status" => "OK"}) + else + return JSON.generate({"status" => "not best", "detail" => errorAr.join(',')}) + end + + end + + app.get "/goalCheckin" do + crossdomain + headjson + + p "/goalCheckin" + p "params : #{params}" + + event_code = params["event"] + zekken_number = params["zekken"] + + goal_time = params['goal_time'] + + begin + goaltime = Time.parse(goal_time) + rescue => error + p error + return JSON.generate({"status" => "ERROR", "detail" => "ゴール時間のパースに失敗しました。Goal time parsing failed."}) + end + + result = getTeamDataByZekken_number(zekken_number, event_code) + + starttime = Time.parse(getEventStartTime(event_code)) + + if result['class_name'].include?('3時間') then + limittime = starttime + (3 * 60 * 60) + elsif result['class_name'].include?('5時間') then + limittime = starttime + (5 * 60 * 60) + #else + elsif result['class_name'].include?("テスト") || result['class_name'].include?("test") then + limittime = starttime + (5 * 60 * 60) + else + message = { + type: 'text', + text: 'エラーコード:DBS-001\nチーム情報の取得に失敗しました。\nゼッケン番号とこのエラーコードを添えて運営に問い合わせて下さい。' + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', 'エラーコード:DBS-001\nチーム情報の取得に失敗しました。\nゼッケン番号とこのエラーコードを添えて運営に問 +い合わせて下さい。') + return JSON.generate({"status" => "NG"}) + end + + if limittime < goaltime then + late_point = goaltime - limittime + if late_point < 60 + late_point = 50 + else + late_point = late_point/60 + 1 + late_point = late_point.floor*50 + end + else + late_point = 0 + end + + inputGoalTime(zekken_number,event_code,goal_time,late_point,set_originbase() + '/photo_none.png') + + Thread.new do + makeScoreboardThread(zekken_number, event_code) + end + + return JSON.generate({"status" => "OK"}) + + end + + app.post "/goal_from_rogapp" do + crossdomain + headjson + + p "goal_from_rogapp" + p "params : #{params}" + + event_code = params["event_code"] + zekken_number = getZekkenNumberByTeamName(params["team_name"], event_code) + if zekken_number == "no zekken number" then + return JSON.generate({"status" => "ERROR", "detail" => "該当するチーム名が存在しません。the team name is not exist."}) + end + + # if cpDoubleCheck(zekken_number, event_code, -1) then + # return JSON.generate({"status" => "ERROR", "detail" => "このチェックポイントは既に登録されています。the check point is already registered."}) + # end + + docpath = set_commonbase() + '/' + event_code + '/' + zekken_number + docpath2 = set_commonbase2() + '/' + event_code + '/' + zekken_number + + if( !Dir.exist?(docpath) )then + Dir.mkdir( docpath, 0755 ) + end + + filename = params['image'].split('/').last + + if filename.to_s.empty? + return JSON.generate({"status" => "ERROR", "detail" => "画像アドレスが指定されていません。Image address is not specified."}) + end + + fullpath = docpath + '/' + filename + + begin + url = params['image'] + encoded_url = URI::DEFAULT_PARSER.escape(url) + puts "uri=#{encoded_url}" + URI.open(encoded_url) do |image| + File.open(fullpath, 'w') do |file| + file.write(image.read) + end + end + rescue => e + p e + return JSON.generate({"status" => "ERROR", "detail" => "写真の保存に失敗しました。Failed to save photo."}) + end + + fullpath2 = s3Uploader("#{event_code}/#{zekken_number}", docpath, filename) + + extension = filename.split('.').last + filenameTh = filename.gsub(".#{extension}", "_th.#{extension}") + + imageOri = Magick::Image.read(fullpath).first + imageTh = imageOri.scale(image_size_width(), image_size_height()) + imageTh.write("temp/#{filenameTh}") + + nextpath = docpath + '/' + filenameTh + FileUtils.mv("/var/www/temp/#{filenameTh}", nextpath) + + goal_time = params['goal_time'] + + begin + goaltime = Time.parse(goal_time) + rescue => error + p error + return JSON.generate({"status" => "ERROR", "detail" => "ゴール時間のパースに失敗しました。Goal time parsing failed."}) + end + + result = getTeamDataByZekken_number(zekken_number, event_code) + starttime = Time.parse(getEventStartTime(event_code)) + + if result['class_name'].include?('3時間') || result['class_name'].include?('3時間') + limittime = starttime + (3 * 60 * 60) + elsif result['class_name'].include?('5時間') || result['class_name'].include?('5時間') + limittime = starttime + (5 * 60 * 60) + elsif result['class_name'].include?("テスト") || result['class_name'].include?("test") + limittime = starttime + (5 * 60 * 60) + else + return JSON.generate({ + "status" => "ERROR", + "detail" => "不明なクラス名です: #{result['class_name']}。運営に問い合わせてください。" + }) + end + + puts "limittime=#{limittime} , goaltime=#{goaltime}" + if limittime < goaltime then + late_point = goaltime - limittime + if late_point < 60 + late_point = 50 + else + late_point = late_point/60 + 1 + late_point = late_point.floor*50 + end + else + late_point = 0 + end + + inputGoalTime(zekken_number, event_code, goal_time, late_point, fullpath2) + + begin + scoreboard_result = makeScoreboard(zekken_number, event_code) + + if scoreboard_result + # S3のURLを使用 + s3_url = scoreboard_result + + # ダウンロード用のURLを生成 + download_url = "/gifuroge/download_scoreboard?event_code=#{event_code}&zekken_number=#{zekken_number}" + + return JSON.generate({ + "status" => "OK", + "scoreboard_url" => s3_url, + "download_url" => download_url + }) + else + return JSON.generate({ + "status" => "OK", + "detail" => "スコアボードの生成に失敗しました。Failed to generate scoreboard." + }) + end + rescue => e + p e + return JSON.generate({ + "status" => "ERROR", + "detail" => "スコアボード生成中にエラーが発生しました: #{e.message}" + }) + end +end + + # 新しいダウンロードエンドポイント(必要に応じて追加) +app.get "/download_scoreboard" do + event_code = params["event_code"] + zekken_number = params["zekken_number"] + + file_path = "#{set_commonbase()}/#{event_code}/scoreboard/#{zekken_number}_scoreboard.pdf" + + if File.exist?(file_path) + send_file(file_path, :filename => "scoreboard_#{zekken_number}.pdf", :type => 'application/pdf') + else + status 404 + "File not found" + end +end + + app.get "/changeGoalTimeCheckin" do + crossdomain + headjson + + p "changeGoalTimeCheckin" + p "params : #{params}" + + event_code = params["event"] + zekken_number = params["zekken"] + + goal_time = params['goal_time'] + + begin + goaltime = Time.parse(goal_time) + rescue => error + p error + return JSON.generate({"status" => "ERROR", "detail" => "ゴール時間のパースに失敗しました。Goal time parsing failed."}) + end + + + result = getTeamDataByZekken_number(zekken_number, event_code) + + starttime = Time.parse(getEventStartTime(event_code)) + + if result['class_name'].include?('3時間') then + limittime = starttime + (3 * 60 * 60) + elsif result['class_name'].include?('5時間') then + limittime = starttime + (5 * 60 * 60) + elsif result['class_name'].include?("テスト") || result['class_name'].include?("test") then + #else + limittime = starttime + (5 * 60 * 60) + else + message = { + type: 'text', + text: 'エラーコード:DBS-001\nチーム情報の取得に失敗しました。\nゼッケン番号とこのエラーコードを添えて運営に問い合わせて下さい。' + } + client.reply_message(event['replyToken'], message) + chatLogger(userId, 'bot', 'text', 'エラーコード:DBS-001\nチーム情報の取得に失敗しました。\nゼッケン番号とこのエラーコードを添えて運営に問 +い合わせて下さい。') + return JSON.generate({"status" => "NG"}) + end + + if limittime < goaltime then + late_point = goaltime - limittime + if late_point < 60 + late_point = 50 + else + late_point = late_point/60 + 1 + late_point = late_point.floor*50 + end + else + late_point = 0 + end + + changeGoalTimeAndLatePoint(zekken_number, event_code, goal_time, late_point) + + return JSON.generate({"status" => "OK"}) + + end + + app.get "/reprint" do + crossdomain + headjson + + p "reprint" + p "params : #{params}" + + event_code = params["event"] + zekken_number = params["zekken"] + + Thread.new do + makeScoreboardThread(zekken_number, event_code, "true") + end + + return JSON.generate({"status" => "OK"}) + + end + + app.get "/serviceCheckTrue" do + crossdomain + headjson + + p "serviceCheckTrue" + p "params : #{params}" + + event_code = params["event"] + zekken_number = params["zekken"] + serial_number = params["sn"] + + result = addBuyFlagTrue(serial_number, zekken_number, event_code) + + if result == "OK" then + return JSON.generate({"status" => "OK"}) + else + return JSON.generate({"status" => "ERROR"}) + end + + end + + app.get "/serviceCheckFalse" do + crossdomain + headjson + + p "serviceCheckFalse" + p "params : #{params}" + + event_code = params["event"] + zekken_number = params["zekken"] + serial_number = params["sn"] + + result = addBuyFlagFalse(serial_number, zekken_number, event_code) + + if result == "OK" then + return JSON.generate({"status" => "OK"}) + else + return JSON.generate({"status" => "ERROR"}) + end + + end + + app.get "/getYetCheckSeeviceList" do + crossdomain + headjson + + p "getYetCheckSeeviceList" + p "params : #{params}" + + event_code = params["event"] + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'gps_detail_fix' ) + + where = "event_code = '#{event_code}' AND origin_buy_point != 0 ORDER BY create_at DESC" + #where = "event_code = '#{event_code}' AND buy_flag = false ORDER BY create_at DESC" + + list = anytable.find2(where) + result = [] + + list.each { |rec| + result.push(rec) + } + + @pgconn.disconnect + + result2 = {} + + result2 = {"status" => "OK"} + + result2["detail"] = result + + return JSON.generate(result2) + + end + + +#==================================== +# 登録周り API +#==================================== + +app.post "/register_team" do + crossdomain + headjson + + p "/register_team" + p "params : #{params}" + + zekken_number = params["zekken_number"] + event_code = params["event_code"] + team_name = params["team_name"] + class_name = params["class_name"] + password = params["password"] + + # パラメータの値を表示 + puts "Received parameters:" + puts "zekken_number: #{zekken_number.inspect}" + puts "event_code: #{event_code.inspect}" + puts "team_name: #{team_name.inspect}" + puts "class_name: #{class_name.inspect}" + puts "password: #{password.inspect}" + + # 必須パラメータのチェック(修正) + missing_params = [] + [ + ['zekken_number', zekken_number], + ['event_code', event_code], + ['team_name', team_name], + ['class_name', class_name], + ['password', password] + ].each do |name, value| + missing_params << name if value.nil? || value.to_s.strip.empty? + end + + if missing_params.any? + return JSON.generate({ + "status" => "ERROR", + "detail" => "Missing or empty required parameters: #{missing_params.join(', ')}" + }) + end + + # データベース接続 + @pgconn = UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost", "mobilous", 0, dbname) + + # team_tableの取得 + team_table = UserPostgresTable.new + team_table.useTable(@pgconn, 'team_table') + + # 既存のチームをチェック + existing_team = team_table.findOne("zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'") + if existing_team + @pgconn.disconnect + return JSON.generate({ + "status" => "ERROR", + "detail" => "Team with this zekken number and event code already exists" + }) + end + + # 新しいチームの登録 + record = { + "zekken_number" => zekken_number, + "event_code" => event_code, + "team_name" => team_name, + "class_name" => class_name, + "password" => password + } + + begin + sql = team_table.makeInsertKeySet(record.keys, record) + puts "Executing SQL: #{sql}" # SQLクエリをログ出力 + result = team_table.insertExec(sql) + if result + @pgconn.disconnect + return JSON.generate({"status" => "OK", "detail" => "Team registered successfully"}) + else + @pgconn.disconnect + return JSON.generate({"status" => "ERROR", "detail" => "Failed to register team"}) + end + rescue PG::UniqueViolation + @pgconn.disconnect + return JSON.generate({ + "status" => "ERROR", + "detail" => "Team with this zekken number and event code already exists" + }) + rescue => error + p error + @pgconn.disconnect + return JSON.generate({"status" => "ERROR", "detail" => "Database error: #{error.message}"}) + end +end + +app.post "/update_team_name" do + crossdomain + headjson + + p "/update_team_name" + p "params : #{params}" + + zekken_number = params["zekken_number"] + new_team_name = params["new_team_name"] + event_code = params["event_code"] + + # 必須パラメータのチェック + if [zekken_number, new_team_name, event_code].any?(&:nil?) + return JSON.generate({"status" => "ERROR", "detail" => "Missing required parameters"}) + end + + @pgconn = UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost", "mobilous", 0, dbname) + + rec = {"team_name" => new_team_name} + where = "zekken_number = '#{zekken_number}' AND event_code = '#{event_code}'" + + begin + result = @pgconn.update("team_table", rec, where) + if result + @pgconn.disconnect + return JSON.generate({"status" => "OK", "detail" => "Team name updated successfully"}) + else + @pgconn.disconnect + return JSON.generate({"status" => "ERROR", "detail" => "Failed to update team name or no matching record found"}) + end + rescue => error + p error + @pgconn.disconnect + return JSON.generate({"status" => "ERROR", "detail" => "Database error: #{error.message}"}) + end +end + +app.post '/input_cp' do + content_type :json + request.body.rewind + data = JSON.parse(request.body.read) + + zekken_number = data['zekken_number'] + event_code = data['event_code'] + cp_number = data['cp_number'] + image_address = data['image_address'] + + result = inputCPnumber(zekken_number, event_code, cp_number, image_address) + + status 200 + { result: result }.to_json +end + +#==================================== +# chatLogViewer API +#==================================== + +app.get "/get_chatlog" do + crossdomain + headjson + + p "get_chatlog" + p "params : #{params}" + + event_code = params["event"] + zekken_number = params["zekken"] + + userid = getUserIdByZekkenNumber(zekken_number, event_code) + + if userid == "no zekken number" then + return JSON.generate({"status" => "ERROR", "detail" => "該当するユーザーを発見出来ませんでした"}) + end + + user_name = getUserName(userid)["user_name"] + + @pgconn=UserPostgres.new + dbname = set_dbname() + @pgconn.connectPg("localhost","mobilous",0,dbname) + anytable=UserPostgresTable.new + anytable.useTable( @pgconn,'chat_log' ) + + where = "userid = '#{userid}' ORDER BY serial_number DESC" + + list = anytable.find2(where) + result = [] + + list.each { |rec| + result.push(rec) + } + + @pgconn.disconnect + + result2 = {} + + result2 = {"status" => "OK"} + + result2["detail"] = result + + result2["name"] = user_name + + return JSON.generate(result2) + +end + +#==================================== +# user admin API +#==================================== + + app.get "/teamRegister" do + crossdomain + headjson + + p "/teamRegister" + p "params : #{params}" + + event = params["event"] + class_name = params["class"] + zekken = params["zekken"] + team = params["team"] + pass = params["pass"] + + inputTeamData(event,class_name,zekken,team,pass) + + return JSON.generate({"status" => "OK"}) + + end + + app.get "/zekkenMaxNum" do + crossdomain + headjson + + p "/zekkenMaxNum" + p "params : #{params}" + + event = params["event"] + + list = getZekkenListByTT(event) + + numList = [] + + list.each do |rec| + numList.push(rec.split('-')[1].to_i) + end + + result = numList.max + + if result == nil then + result = 0 + end + + return JSON.generate({"status" => "OK", "result" => result}) + + end + + app.get "/zekkenDoubleCheck" do + + crossdomain + headjson + + p "/zekkenDoubleCheck" + p "params : #{params}" + + zekken = params['zekken'] + event = params['event'] + + list = getZekkenListByTT(event) + + result = false + + list.each do |rec| + if rec == zekken then + result = true + break + end + end + + return JSON.generate({"status" => "OK", "result" => result}) + + end + + app.get "/teamClassChanger" do + crossdomain + headjson + + p "/teamClassChanger" + p "params : #{params}" + + zekken = params['zekken'] + event = params['event'] + new_class = params['new_class'] + + result = changeTeamClass(zekken, event, new_class) + + return JSON.generate({"status" => result}) + + end + +#==================================== +# CP一覧シート作成用API +#==================================== + + app.post "/makeCpListSheet" do + crossdomain + + p "/makeCpListSheet" + p "params : #{params}" + + event_code = params["event"] + cp_csv = params["cp_csv"] + sponsor_csv = params["sponsor_csv"] + + insert_record = {} + insert_header = [] + + event_data = getEventData(event_code) + + insert_header.push("event_name") + insert_record["event_name"] = event_data["event_name"] + + insert_header.push("event_day") + insert_record["event_day"] = event_data["event_day"] + + i = 1 + + CSV.foreach(cp_csv[:tempfile], headers: true) do |row| + + #puts "row=#{row}" + + if row["sub_loc_id"].to_s.start_with?('#-1') then + next + end + + insert_header.push("sub_loc_id_#{i}") + insert_record["sub_loc_id_#{i}"] = row["sub_loc_id"] + + insert_header.push("loc_name_#{i}") + insert_record["loc_name_#{i}"] = row["loc_name"] + + insert_header.push("photo_#{i}") + insert_record["photo_#{i}"] = "#{set_commonbase()}/#{event_code}/cps/#{row["photos"]}" + + insert_header.push("remark_#{i}") + insert_record["remark_#{i}"] = row["remark"] + + insert_header.push("tags_#{i}") + insert_record["tags_#{i}"] = row["tags"] + + i = i + 1 + end + + CSV.foreach(sponsor_csv[:tempfile], headers: true) do |row| + + for ii in 1..30 do + if row["sponsor_#{ii}"] != nil && row["sponsor_#{ii}"] != "" then + insert_header.push("sponsor_#{ii}") + insert_record["sponsor_#{ii}"] = row["sponsor_#{ii}"] + end + end + + end + + sn = getMaxNumByCLS().to_i + 1 + + insert_header.push("serial_number") + insert_record["serial_number"] = sn + + #p "insert_header : #{insert_header}" + #p "insert_record : #{insert_record}" + + inputCpListSheet(insert_header, insert_record) + + #ここから用紙生成プロセス + + #$bean.read_bean + + #username = $bean.username + username = "natnats" + + record = insert_record + + record["num_image"] = i + 1 + + document = "cpListSheet" + + ExcelObject.resetClass + + doc = AppExeExcelDoc.new + #doc = AppExeGeneralDocument.new + #doc.init( username,0,document,"jp","/var/www/docbase","/home/mobilousInstance" ) # <== "/home/mobilousInstance" を出力先のベースフォルダーにしてください。 + doc.init( username,0,document,"jp","/var/www/docbase","/home/ubuntu" ) # <== "/home/mobilousInstance" を出力先のベースフォルダーにしてください。 + + pgconn=UserPostgres.new + dbname = set_dbname() + pgconn.connectPg("localhost","mobilous",0,dbname) + + rec = JSON.parse( JSON.generate(record) ) + #@sheetname = sheet + #filename = doc.makeReport( pgconn,rec,"outfile.xlsx",0 ) # ==> Use ini file defnition 2021-11-15 + doc.makeReport( pgconn,rec ) + + # make a excel file under /var/www/docbase/(@username)/(@projectno)/ + + #file_path = filename.to_s.gsub(/wrote excel file on /,"") + #puts "=========> file_path = #{file_path}" + + filename = doc.outfile + file_path = doc.outpath + puts "=========> file_path = #{file_path}, filename = #{filename}" + + content_type "application/xlsx" + attachment "#{file_path}" + + send_file(file_path, :filename => "cpListSheet_#{event_code}.xlsx",:type => "application/xlsx", :disposition => 'attachment') + + end + +#==================================== +# 手動呼び出し用API +#==================================== + + app.get "/makeAllScoreboard" do + crossdomain + headjson + + p "/makeAllScoreboard" + p "params : #{params}" + + event_code = params["event"] + + zekken_list = getZekkenListByTT(event_code) + + if zekken_list == nil || zekken_list == [] then + return JSON.generate({"status" => "ERROR", "detail" => "no zekkens"}) + end + + complete_list = {} + fail_list = [] + error_list = {} + + zekken_list.each do |zekken| + begin + p "zekken : #{zekken}" + result = makeScoreboardThread(zekken, event_code, false, true) + + if result == "no data erropr" then + fail_list.push(zekken) + else + complete_list[zekken] = result + end + rescue => e + p e + error_list[zekken] = e + end + + end + + return JSON.generate({"complete" => complete_list, "fail" => fail_list, "error" => error_list}) + + end + +#==================================== +# rog app API +#==================================== + + app.post "/start_from_rogapp" do + p "/start_from_rogapp" + crossdomain + headjson + + p "start_from_rogapp" + p "params : #{params}" + + + + event_code = params["event_code"] + zekken_number = getZekkenNumberByTeamName(params["team_name"], event_code) + if zekken_number == "no zekken number" then + return JSON.generate({"status" => "ERROR", "detail" => "該当するチーム名が存在しません。the team name is not exist."}) + end + + #FC岐阜コラボの時はスタートでチェックポイントを削除しないように(同じルートを別日に回ることがあるため) + # removeAllGI(zekken_number, event_code) + + inputCPnumber(zekken_number,event_code,-2,set_originbase() + '/start.png') + + # # bonus_point_flagにデータがあったらポイント追加 + # if checkBonusPointFlag(zekken_number, event_code) + # inputCPnumber(zekken_number, event_code, 102, set_originbase() + '/start.png') + # end + + + return JSON.generate({"status" => "OK"}) + + end + + app.get "/practice" do + crossdomain + headjson + practice_text = "practice" + return practice_text + end + + + app.post "/checkin_from_rogapp" do + crossdomain + headjson + + p "checkin_from_rogapp" + p "params : #{params}" + + event_code = params["event_code"] + zekken_number = getZekkenNumberByTeamName(params["team_name"], event_code) + + # ディレクトリパスの構築 + base_path = "/var/www/html/images/gifuRoge" + full_path = File.join(base_path, event_code, zekken_number.to_s) + + # ディレクトリの作成(既に存在する場合は何もしない) + begin + FileUtils.mkdir_p(full_path) unless File.directory?(full_path) + rescue Errno::EACCES => e + puts "エラー: ディレクトリ作成の権限がありません。 #{e.message}" + return JSON.generate({"status" => "ERROR", "detail" => "サーバー内部エラー:ディレクトリ作成の権限がありません。"}) + rescue => e + puts "エラー: ディレクトリ作成中に問題が発生しました。 #{e.message}" + return JSON.generate({"status" => "ERROR", "detail" => "サーバー内部エラー:ディレクトリ作成中に問題が発生しました。"}) + end + + if zekken_number == "no zekken number" then + return JSON.generate({"status" => "ERROR", "detail" => "該当するチーム名が存在しません。the team name is not exist."}) + end + cp_number = params["cp_number"] + + if cp_number.to_i == -1 || cp_number.to_i == -2 then + return JSON.generate({"status" => "ERROR", "detail" => "スタートやゴールをチェックインする時はそれぞれ専用のAPIを使ってチェックインしてください。When checking in for the start or finish, please use the respective dedicated API to check in."}) + end + + if cpDoubleCheck(zekken_number, event_code, cp_number) then + return JSON.generate({"status" => "ERROR", "detail" => "このチェックポイントは既に登録されています。the check point is already registered."}) + end + + docpath = set_commonbase() + '/' + event_code + '/' + zekken_number + docpath2 = set_commonbase2() + '/' + event_code + '/' + zekken_number + + if( !Dir.exist?(docpath) )then + if( Dir.mkdir( docpath,0755 ) == 0 ) then + end + end + + filename = params['image'].split('/').last + + if filename == '' || filename == nil then + return JSON.generate({"status" => "ERROR", "detail" => "画像アドレスが指定されていません。Image address is not specified."}) + end + + fullpath = docpath + '/' + filename + + begin + url = params['image'] + encoded_url = URI::DEFAULT_PARSER.escape(url) + puts "uri=#{encoded_url}" + URI.open(encoded_url) do |image| + File.open(fullpath, 'w') do |file| + file.write(image.read) + end + end + rescue => e + p e + return JSON.generate({"status" => "ERROR", "detail" => "写真の保存に失敗しました。Failed to save photo."}) + end + + fullpath2 = s3Uploader("#{event_code}/#{zekken_number}",docpath,filename) + + extension = filename.split('.').last + + filenameTh = filename.gsub(".#{extension}","_th.#{extension}") + + imageOri = Magick::Image.read(fullpath).first + imageTh = imageOri.scale(image_size_width(), image_size_height()) + imageTh.write("temp/#{filenameTh}") + + nextpath = docpath + '/' + filenameTh + + FileUtils.mv("/var/www/temp/#{filenameTh}",nextpath) + # File.delete(fullpath) + + fullpath = fullpath2 + + inputCPnumber(zekken_number, event_code, cp_number, fullpath) + + return JSON.generate({"status" => "OK"}) + + end + + app.post "/remove_checkin_from_rogapp" do + crossdomain + headjson + + p "remove_checkin_from_rogapp" + p "params : #{params}" + begin + event_code = params["event_code"] + zekken_number = getZekkenNumberByTeamName(params["team_name"], event_code) + if zekken_number == "no zekken number" then + return JSON.generate({"status" => "ERROR", "detail" => "該当するチーム名が存在しません。the team name is not exist."}) + end + cp_number = params["cp_number"] + + sn = getSerialNumberByCpNumber(zekken_number, event_code, cp_number) + + if sn == 'no sn' then + return JSON.generate({"status" => "ERROR", "detail" => "該当するチェックインが見つかりません。No corresponding checkin found."}) + end + + command = "DELETE #{sn}" + + result = deleteRegister('API', zekken_number, event_code, command, nil, nil, true) + + # チェックポイントが2回登録されている場合があるための処理 ここから + sn = getSerialNumberByCpNumber(zekken_number, event_code, cp_number) + + if sn != 'no sn' then + command = "DELETE #{sn}" + + result = deleteRegister('API', zekken_number, event_code, command, nil, nil, true) + end + # チェックポイントが2回登録されている場合があるための処理 ここまで + + return JSON.generate({"status" => "OK"}) + + rescue => e + return JSON.generate({"status" => "ERROR", "detail" => "予期せぬエラー undefined error #{e}"}) + end + + end + + app.get "/get_team_list" do + crossdomain + headjson + + p "get_team_list" + + p "params : #{params}" + + event_code = params["event_code"] + if event_code == '' then + event_code = nil + end + + return JSON.generate(getTeamList(event_code)) + end + + #元のゴール処理。fc岐阜用に同じ名前で修正したものを別のとこに作ってます + # app.post "/goal_from_rogapp" do + # crossdomain + # headjson + + # p "goal_from_rogapp" + # p "params : #{params}" + + # event_code = params["event_code"] + # zekken_number = getZekkenNumberByTeamName(params["team_name"], event_code) + # if zekken_number == "no zekken number" then + # return JSON.generate({"status" => "ERROR", "detail" => "該当するチーム名が存在しません。the team name is not exist."}) + # end + + + + # # if cpDoubleCheck(zekken_number, event_code, -1) then + # # return JSON.generate({"status" => "ERROR", "detail" => "このチェックポイントは既に登録されています。the check point is already registered."}) + # # end + + # docpath = set_commonbase() + '/' + event_code + '/' + zekken_number + # docpath2 = set_commonbase2() + '/' + event_code + '/' + zekken_number + + # if( !Dir.exist?(docpath) )then + # Dir.mkdir( docpath, 0755 ) + # end + + # filename = params['image'].split('/').last + + # if filename.to_s.empty? + # return JSON.generate({"status" => "ERROR", "detail" => "画像アドレスが指定されていません。Image address is not specified."}) + # end + + # fullpath = docpath + '/' + filename + + # begin + # url = params['image'] + # encoded_url = URI::DEFAULT_PARSER.escape(url) + # puts "uri=#{encoded_url}" + # URI.open(encoded_url) do |image| + # File.open(fullpath, 'w') do |file| + # file.write(image.read) + # end + # end + # rescue => e + # p e + # return JSON.generate({"status" => "ERROR", "detail" => "写真の保存に失敗しました。Failed to save photo."}) + # end + + # fullpath2 = s3Uploader("#{event_code}/#{zekken_number}", docpath, filename) + + # extension = filename.split('.').last + # filenameTh = filename.gsub(".#{extension}", "_th.#{extension}") + + # imageOri = Magick::Image.read(fullpath).first + # imageTh = imageOri.scale(image_size_width(), image_size_height()) + # imageTh.write("temp/#{filenameTh}") + + # nextpath = docpath + '/' + filenameTh + # FileUtils.mv("/var/www/temp/#{filenameTh}", nextpath) + + # goal_time = params['goal_time'] + + # begin + # goaltime = Time.parse(goal_time) + # rescue => error + # p error + # return JSON.generate({"status" => "ERROR", "detail" => "ゴール時間のパースに失敗しました。Goal time parsing failed."}) + # end + + # result = getTeamDataByZekken_number(zekken_number, event_code) + # starttime = Time.parse(getEventStartTime(event_code)) + + # if result['class_name'].include?('3時間') || result['class_name'].include?('3時間') + # limittime = starttime + (3 * 60 * 60) + # elsif result['class_name'].include?('5時間') || result['class_name'].include?('5時間') + # limittime = starttime + (5 * 60 * 60) + # elsif result['class_name'].include?("テスト") || result['class_name'].include?("test") + # limittime = starttime + (5 * 60 * 60) + # else + # return JSON.generate({ + # "status" => "ERROR", + # "detail" => "不明なクラス名です: #{result['class_name']}。運営に問い合わせてください。" + # }) + # end + + # puts "limittime=#{limittime} , goaltime=#{goaltime}" + # if limittime < goaltime then + # late_point = goaltime - limittime + # if late_point < 60 + # late_point = 50 + # else + # late_point = late_point/60 + 1 + # late_point = late_point.floor*50 + # end + # else + # late_point = 0 + # end + + # inputGoalTime(zekken_number, event_code, goal_time, late_point, fullpath2) + + # Thread.new do + # makeScoreboardThread(zekken_number, event_code) + # end + + # return JSON.generate({"status" => "OK"}) + # end + + app.post "/get_waypoint_datas_from_rogapp" do + crossdomain + headjson + + begin + + p "/get_waypoint_datas_from_rogapp" + p "params : #{params}" + + team_name = params["team_name"] + event_code = params["event_code"] + list = params["waypoints"] + + zekken_number = getZekkenNumberByTeamName(params["team_name"],event_code) + if zekken_number == "no zekken number" then + return JSON.generate({"status" => "ERROR", "detail" => "該当するチーム名が存在しません。the team name is not exist."}) + end + + data = [] + + list.each do |rec| + + line = [] + line.push(rec['latitude']) + line.push(rec['longitude']) + line.push(rec['time']) + + data.push(line) + + end + + filebase = "#{set_commonbase}/#{event_code}/#{zekken_number}" + + output_file = "#{filebase}/waypoints.csv" + + if (File.exist?(output_file)) then + input_data = CSV.read(output_file) + data = input_data + data + end + + if (!File.exist?(filebase)) then + if( Dir.mkdir( filebase,0755 ) == 0 ) then + end + end + + CSV.open(output_file, 'w') do |csv| + data.each do |row| + csv << row + end + end + + return JSON.generate({"status" => "OK"}) + + rescue => e + p e + return JSON.generate({"status" => "ERROR", "detail" => "予期せぬエラーが発生しました。undefined error : #{e}"}) + end + + end + + + app.get "/check_event_code" do + crossdomain + headjson + + p "check_event_code" + p "params : #{params}" + + zekken_number = params['zekken_number'] + password = params['pw'] + + result = zekkenAuthorization(zekken_number, password) + + if result["result"] == "ERROR" then + return JSON.generate({"status" => "ERROR"}) + else + return JSON.generate({"status" => "OK", "event_code" => result["event_code"]}) + end + + end + + end + + end +end + diff --git a/LineBot/userpostgres.rb b/LineBot/userpostgres.rb new file mode 100644 index 0000000..0a01b66 --- /dev/null +++ b/LineBot/userpostgres.rb @@ -0,0 +1,1087 @@ +require "rubygems" +# -*- coding: utf-8 -*- + +require 'pg' +require 'open-uri' +#require 'mongo' +require 'fastercsv' +require '/var/www/lib/alertError.rb' + +class UserPostgres + def createCommDB host,dbname + if host!=nil then + tempconn = PG.connect(:host =>"#{host}.mobilous.com", :port =>"5432", :dbname => "mobilouscomm", :user =>"mobilous", :password => "ctcpy9823\"x~") + else + tempconn = PG.connect(:host =>"localhost", :port =>"5432", :dbname => "mobilouscomm", :user =>"mobilous", :password => "ctcpy9823\"x~") + end + sql = "create database mobilouscomm" + tempconn.exec(sql) + end + + def createDB host,dbname + begin + if host!=nil and host!='localhost' then + tempconn = PG.connect(:host =>"#{host}.mobilous.com", :port =>"5432", :dbname => "mobilouscomm", :user =>"mobilous", :password => "ctcpy9823\"x~") + else + tempconn = PG.connect(:host =>"localhost", :port =>"5432", :dbname => "mobilouscomm", :user =>"mobilous", :password => "ctcpy9823\"x~") + end + sql = "create database #{dbname}" + tempconn.exec(sql) + rescue + puts "The database #{dbname} is not existing." + Alert::sendAlertEmail( "userpostgres.rb","createDB","#{host},#{dbname}","#{e}:#{host},#{dbname}","Akira" ) + end + end + + def dropDB host,projectid + begin + dbname = "db_#{projectid}" + if host!=nil then + tempconn = PG.connect(:host =>"#{host}.mobilous.com", :port =>"5432", :dbname => "mobilouscomm", :user =>"mobilous", :password => "ctcpy9823\"x~") + else + tempconn = PG.connect(:host =>"localhost", :port =>"5432", :dbname => "mobilouscomm", :user =>"mobilous", :password => "ctcpy9823\"x~") + end + sql = "drop database #{dbname}" + puts "dropDB : #{sql}" + tempconn.exec(sql) + rescue + puts "The database #{dbname} is not existing." + Alert::sendAlertEmail( "userpostgres.rb","dropDB","#{host},#{projectid}","#{e}:#{host},#{projectid}","Akira" ) + end + end + + def connectPg host,username,projectid,dbname,psql_port=nil,console=nil + + @debug_base = false # エラーで一時停止する。 + @debug_log = false + + # dbname : "mobilouscomm" or "db_(projectno)" + @dbname =dbname + @username = username + @projectid = projectid + if( psql_port==nil )then + port = "5432" + else + port = psql_port + end + + if( host!=nil )then + host.gsub!(".mobilous.com","") + end + + if( console==nil ) then + #@password = "ctcpy9823\"x~" + @password = "admin123456" + if host!=nil then + @host=host + if( @host=="localhost" )then + hosturl=@host + else + hosturl="#{host}.mobilous.com" + end + else + @host=host + hosturl="localhost" + end + #username = "mobilous" + username = "admin" + else + @host=host + hosturl = @host + @password = "mob!kaihat$ush@" + end + + #puts "host=#{host},hosturl=#{hosturl},username=#{username},projectid=#{projectid},dbname=#{dbname}" + begin + #@connection = PGconn.connect(:host => hosturl, :port => port, :dbname => dbname, :user =>username, :password => @password, :connect_timeout => 180000 ) + @connection = PG.connect(:host => hosturl, :port => port, :dbname => dbname, :user =>username, :password => @password, :connect_timeout => 180000 ) + rescue => e + p "Error on connectPg : host=#{host},username=#{username},projectid=#{projectid},dbname=#{dbname},port=#{psql_port},console=#{console}, pass=#{@password} ==> #{e}" + puts caller + raise StandardError,"Error on connectPg : host=#{host},username=#{username},projectid=#{projectid},dbname=#{dbname},port=#{psql_port},console=#{console}, pass=#{@password} ==> #{e}" + + #Alert::sendAlertEmail( "userpostgres.rb","connectPG","#{host},#{username},#{projectid},#{dbname},#{psql_port},#{console}","#{e}:#{host},#{projectid}","Akira" ) + #createDB( host,dbname ) + #@connection = PGconn.connect(:host => hosturl, :port => port, :dbname => dbname, :user =>username, :password => @password) + #exit(1) + end + + #p "Connected database #{@dbname} on host #{@host}" + if(false)then + p "-"*80 + puts caller + p "-"*80 + end + return @connection + end + + def connectConsolePg host,username,pass,dbname,port + #puts "host=#{host},username=#{username},pass=#{pass},dbname=#{dbname},port=#{port}" + @connection = PG.connect(:host => host, :port => port, :dbname => dbname, :user =>username, :password => pass) + return @connection + end + + def exec sql + begin + res=@connection.exec( sql ) + #p sql + p "exec: #{res},#{res.result_error_message}" + return res + rescue =>e + puts "Error: #{e}" + puts "Executing Error : #{sql}" + puts caller + #Alert::sendAlertEmail( "userpostgres.rb","exec",sql,"#{e}: #{sql}","Akira" ) + + return "(#{e}) : #{sql}" + end + end + + def disconnect + begin + @connection.close + rescue => e + p "Error on disconnectPg : #{e}" + #gets + #Alert::sendAlertEmail( "userpostgres.rb","disconnect","","#{e}","Akira" ) + end + end + + def createTable tabledef,console=nil + mobuser='mobilous' + if( console )then + mobuser='mobilousdbuser' + end + + servicename = tabledef["servicename"] + if servicename!="Mobilous" then + puts "#{servicename} is not Mobilous. So, skip to create db." + end + + tablename = tabledef["tablename"] + csvfilename = tabledef["csvfilename"] + fields = tabledef["fields"] + primarykeys = Array.new + + tbl = UserPostgresTable.new + tbl.useTable( self ,tablename ) + tbl.setTableDef( tabledef ) + + createcom = "create table #{tablename} (" + count=0 + fields.each { |field| + if count>0 then + createcom = "#{createcom}," + end + count=count+1 + + #"dbType" : "text", + #"fieldname" : "bigimage", + #"primary" : false, + #"autoinc" : false, + #"description" : "" + + fieldname = field["fieldname"] + fieldname.gsub!("-","_") + type = field["dbType"] + if( type==nil )then + type="text" + end + if( type=="datetime" )then + type="timestamp" + end + if( type=="double" )then + type="float" + end + primary = field["primary"] + autoinc = field["autoinc"] + + if primary==true then + primarykeys.push(fieldname) + end + if autoinc==true then + tmp = "#{createcom} #{fieldname} serial" + else + tmp = "#{createcom} #{fieldname} #{type}" + end + + createcom = tmp + } + + if primarykeys.count()>0 then + createcom = "#{createcom},row_index serial, primary key( " + countb=0 + primarykeys.each { |pkey| + if countb>0 then + createcom = "#{createcom}," + end + createcom = "#{createcom} #{pkey}" + countb += 1 + } + createcom = "#{createcom}) );" + else + createcom = "#{createcom} );" + end + + puts "SQL = #{createcom}" + res = @connection.exec(createcom) + + grant = "GRANT ALL PRIVILEGES ON DATABASE #{@dbname} TO postgres ;" + #puts "SQL = #{grant}" + res = @connection.exec(grant) + grant = "GRANT ALL PRIVILEGES ON DATABASE #{@dbname} TO #{mobuser} ;" + #puts "SQL = #{grant}" + res = @connection.exec(grant) + grant = "GRANT ALL PRIVILEGES ON SCHEMA public TO #{mobuser} ;" + + #puts "SQL = #{grant}" + res = @connection.exec(grant) + + if csvfilename!="" then + tbl.loadCSVfromMongo( @host,@username,@projectid,csvfilename ) + end + end + + + def createTables tabledefs,viewdefs + #tbl = UserPostgresTable.new + if( tabledefs==nil )then + puts "ERROR =====> no tabledefs is defined." + return + end + + tbls = Array.new + views = Array.new + triggers = Array.new + procedures = Array.new + + tabledefs.each { |tabledef| + #puts "create table tabledef=#{tabledef}" + if( tabledef!=nil )then + if( tabledef["view"]==true )then + puts "===>Reserve Create View #{tabledef['tablename']}" + views.push( tabledef ) + + elsif( tabledef["tablename"]!=nil && tabledef["tablename"]!="" )then + puts "===>Create Table #{tabledef['tablename']}" + tbls.push( tabledef ) + + elsif( tabledef["procedure"]==true )then + puts "===>Reserve create procedure #{tabledef['tablename']}" + procedures.push( tabledef ) + + elsif( tabledef["trigger"]==true )then + puts "===>reserve create trigger #{tabledef['tablename']}" + triggers.push( tabledef ) + + else + puts "table name is blank : #{tabledef['tablename']}" + end + end + } + + puts "----------> procedures = #{procedures}" + + triggers.each { |trigdef| + dropTrigger( trigdef ) + } + + procedures.each { |procdef| + dropProcedure( procdef ) + } + + + views.each { |viewdef| + dropView( viewdef["tablename"] ) + } + + tbls.each { |tabledef| + dropTable( tabledef["tablename"] ) + + createTable( tabledef ) + } + views.each { |viewdef| + createView( viewdef ) + } + + procedures.each { |procdef| + createProcedure( procdef ) + } + + triggers.each { |trigdef| + createTrigger( trigdef ) + } + end + + def dropTable tablename + begin + sql = "drop table #{tablename}" + @connection.exec(sql) + puts "drop #{tablename} is done. #{sql}" + return true + rescue => e + puts " Error on dropTable #{tablename}: #{e}" + Alert::sendAlertEmail( "userpostgres.rb","dropTable",tablename,"#{e}:#{tablename}","Akira" ) + return false + end + end + + def dropView viewname + begin + sql = "drop view #{viewname}" + @connection.exec(sql) + puts "drop #{viewname} is done. #{sql}" + return true + rescue => e + puts " Error on dropView #{viewname}: #{e}" + Alert::sendAlertEmail( "userpostgres.rb","dropView",viewname,"#{e}:#{viewname}","Akira" ) + return false + end + end + + def createView viewdef + if( viewdef==nil )then + return + end + + begin + puts "#{viewdef["viewname"]} will be executed as #{viewdef["query"]}" + @connection.exec(viewdef["query"]) + puts "create #{viewdef["viewname"]} is done." + rescue => e + puts " Error on createView #{viewdef["viewname"]}: #{e}" + Alert::sendAlertEmail( "userpostgres.rb","createView",viewdef,"#{e}:#{viewdef}","Akira" ) + end + end + + def createViews viewdefs + if viewdefs==nil then return end + viewdefs.each { |viewdef| + createView( viewdef ) + } + end + + def dropProcedure procdef + # 改行で分ける。 + # + begin + funcname = procdef["procedurename"] + if( funcname.index("(")==nil )then + funcname = "#{procdef['procedurename']}()" + end + sql = "drop function if exists #{funcname}" + @connection.exec(sql) + puts "drop #{funcname} is done. #{sql}" + rescue => e + puts " Error on dropProcedure #{procdef['procedurename']}: #{e}" + Alert::sendAlertEmail( "userpostgres.rb","dropProcedure",procdef,"#{e}:#{procdef}","Akira" ) + end + end + + def createProcedure procdef + + begin + #puts "#{procdef['procedurename']} will be executed as #{procdef['script']}" + @connection.exec(procdef["script"]) + puts "create #{procdef["procedurename"]} is done." + rescue => e + puts " Error on createProcedure #{procdef['procedurename']}: #{e}" + Alert::sendAlertEmail( "userpostgres.rb","createProcedure",procdef,"#{e}:#{procdef}","Akira" ) + end + + end + + + def dropTrigger trigdef + begin + watch = trigdef['watch_table'] + if( watch==nil ) then + script = trigdef['script'] + a = script.split("\r\n") # 改行分割 + b = a[0].split("on") + watch = b[1] + end + sql = "drop trigger if exists #{trigdef['triggername']} on #{watch}" + puts "SQL=#{sql}" + @connection.exec(sql) + puts "drop #{trigdef['triggername']} is done. #{sql}" + rescue => e + puts " Error on dropTrigger #{trigdef['triggername']}: #{e}" + Alert::sendAlertEmail( "userpostgres.rb","dropTrigger",trigdef,"#{e}:#{trigdef}","Akira" ) + end + end + + def createTrigger trigdef + begin + puts "#{trigdef['triggername']} will be executed as #{trigdef['script']}" + @connection.exec(trigdef["script"]) + puts "create #{trigdef["triggername"]} is done." + rescue => e + puts " Error on createTrigger (#{trigdef['triggername']}): #{e}" + Alert::sendAlertEmail( "userpostgres.rb","createTrigger",trigdef,"#{e}:#{trigdef}","Akira" ) + end + end + + + def selectExec sql + begin + result = @connection.exec(sql) + puts "selectExec: num of rec is #{result.ntuples} for #{sql}" # ヒットした行 + return result + rescue => e + error_message = " Error on selectExec (#{sql}): #{e}" + puts error_message + puts caller + + # エラーをログファイルに書き込む + log_error(error_message) + + return nil + end + end + + # エラーをログファイルに書き込むメソッド + def log_error(message) + File.open('database_errors.log', 'a') do |file| + file.puts "#{Time.now}: #{message}" + end + rescue => e + puts "Failed to write to log file: #{e.message}" + end + + def insert tablename,record + sqlkey = "" + sqlval = "" + i=0 + record.each{ |key,value| + if( i==0 )then + sqlkey = key + sqlval = "'#{value}'" + else + sqlkey = "#{sqlkey},#{key}" + sqlval = "#{sqlval},'#{value}'" + end + i += 1 + } + sql = "insert into #{tablename} (#{sqlkey}) values (#{sqlval})" + #p sql + @connection.exec( sql ) + end + + def update tablename,record,whr + sqlkey = "" + i=0 + record.each{ |key,value| + if( i==0 )then + sqlkey="#{key}='#{value}'" + else + sqlkey="#{sqlkey},#{key}='#{value}'" + end + i += 1 + } + + sql = "update #{tablename} set #{sqlkey} where #{whr}" + @connection.exec( sql ) + #p sql + end + + # https://devlights.hatenablog.com/entry/20080226/p1 + # PostgreSQLにてテーブルやカラムの各種情報を取得するSQL + def getPrimaryKeys tablename + sql = "select ccu.column_name as COLUMN_NAME from information_schema.table_constraints tc,information_schema.constraint_column_usage ccu where tc.table_catalog='#{@dbname}' and tc.table_name='#{tablename}' and tc.constraint_type='PRIMARY KEY' and tc.table_catalog=ccu.table_catalog and tc.table_schema=ccu.table_schema and tc.table_name=ccu.table_name and tc.constraint_name=ccu.constraint_name" + keys = @connection.exec(sql) + return keys + end + + def getFieldList tablename + sql = "select * from information_schema.columns where table_catalog='#{@dbname}' and table_name='#{tablename}' order by ordinal_position" + fieldlist = @connection.exec(sql) + fields = Hash.new + fieldlist.each { |rec| + key = rec["column_name"] + fields[key]=rec + } + return fields + # userid userstatus contract_mgr startdate createdatetime + # table_catalog db_532 db_532 db_532 db_532 db_532 + # table_schema public public public public public + # table_name users users users users users + # column_name userid userstatus contract_mgr startdate createdatetime + # ordinal_position 1 6 13 17 20 + # column_default 0 '2018-06-30'::date '2018-06-30 07:00:57.687173+00'::timestamp with time zone + # is_nullable NO YES YES YES YES + # data_type text integer boolean date timestamp with time zone + # character_maximum_length + # character_octet_length 1073741824 + # numeric_precision 32 + # numeric_precision_radix 2 + # numeric_scale 0 + # datetime_precision 0 6 + # interval_type + # interval_precision + # character_set_catalog + # character_set_schema + # character_set_name + # collation_catalog + # collation_schema + # collation_name + # domain_catalog + # domain_schema + # domain_name + # udt_catalog db_532 db_532 db_532 db_532 db_532 + # udt_schema pg_catalog pg_catalog pg_catalog pg_catalog pg_catalog + # udt_name text int4 bool date timestamptz + # scope_catalog + # scope_schema + # scope_name + # maximum_cardinality + # dtd_identifier 1 6 13 18 20 + # is_self_referencing NO NO NO NO NO + # is_identity NO NO NO NO NO + # identity_generation + # identity_start + # identity_increment + # identity_maximum + # identity_minimum + # identity_cycle + # is_generated NEVER NEVER NEVER NEVER NEVER + # generation_expression + # is_updatable YES YES YES YES YES + # + + end + +end + +class UserPostgresTable + def useTable db,tablename + #コレクション選択 + # dbinstance = UserMongoDB.new + # db = dbinstance.useDB( dbname ) + @tablename=tablename + @db = db + if @tablename == nil then + puts "[WARING] tablename(#{tablename})is not existing" + end + end + + def getPrimaryKeys + return @db.getPrimaryKeys( @tablename ) + end + + def getFieldList + return @db.getFieldList( @tablename ) + end + + # 与えたレコードの正当性を補填する。正規化したレコードを戻す。 + def validateFieldData orig + record = Hash.new + fields = @db.getFieldList( @tablename ) + orig.each { |k,v| + field = fields[k] + if( field!=nil )then + udt_name = field["udt_name"] + if( udt_name=="date" || udt_name=="timestamp" || udt_name=="timestamptz" )then + if( v!="" && v!=nil )then + record[k]=v + end + else + record[k]=v + end + end + } + + return record + end + + def insertExec sql + ret = @db.exec(sql) + return true + end + + def exec sql + ret = @db.exec(sql) + if( ret.index( "Executing Error" ) )then + return false + else + return true + end + end + + def tablename + return @tablename + end + + def setTableDef tabledef + @tabledef=tabledef + end + + def tableDef + return @tabledef + end + + def remove cond + puts "delete from #{@tablename} where #{cond}" + @db.exec("delete from #{@tablename} where #{cond}") + end + + def count(where_clause) + sql = "SELECT COUNT(*) FROM #{@tablename}" + sql += " WHERE #{where_clause}" if where_clause && !where_clause.empty? + + result = @db.selectExec(sql) + result[0]['count'].to_i + rescue => e + puts "Database error in count method: #{e.message}" + 0 # エラーの場合は0を返す + end + +# レコード抽出 +# @param conf [text] where 句で使用する検索条件。where以降のみ指定。nil の場合全件抽出。 +# @param sort [text] order by 句で使用するソート条件。order by 以降のみ指定。nil の場合不定。 +# + def find2 conf,sort=nil,columns=nil + #全件取得 + sql = "select " + if columns!=nil then + sql << columns + else + sql << "*" + end + + sql << " from #{@tablename}" + sql << " where #{conf}" if conf!=nil + sql << " order by #{sort}" if sort!=nil + + #p "find2 : #{sql}" + records = @db.selectExec( sql ) + return records + end + +# レコード抽出 +# @param conf [text] where 句で使用する検索条件。where以降のみ指定。nil の場合全件抽出。 +# @param sort [text] order by 句で使用するソート条件。order by 以降のみ指定。nil の場合不定。 +# + + def find_for_relation(conf, sort = nil, columns = nil) + sql = "SELECT " + sql << (columns || "COUNT(g.*)") + sql << " FROM #{@tablename} AS g " + sql << " #{conf}" if conf + sql << " ORDER BY #{sort}" if sort + + @db.selectExec(sql) + rescue => e + puts "Database error in find_for_relation method: #{e.message}" + [] # エラーの場合は空の配列を返す + end + + def get_unique_event_codes_sql(table_name) + sql = "SELECT DISTINCT event_code FROM #{table_name}" + records = @db.selectExec(sql) + # Convert PG::Result to an array of hashes + return records.map { |row| row.to_h } + end + + + + + # この状態ではレコードを返していないのでは? +# find2 を取り敢えず作成した。 + + def find conf + #全件取得 + if( conf!=nil )then + #puts "select * from #{@tablename} where #{conf}" + records = @db.exec("select * from #{@tablename} where #{conf}") + #puts "result :#{records}; records count: #{records.count()}" + return records + else + records = @db.exec("select * from #{@tablename}") + return records + end + end + + def findOne conf + #puts "select * from #{@tablename} where #{conf}" + records = @db.selectExec("select * from #{@tablename} where #{conf}") + #puts records + if( records!=nil )then + if( records.count>0 )then + return records[0] + end + end + return nil + end + + def makeKeyCondition keys,record + str = "" + count = 0 + keys.each{|key| + val = record[key] + if( count>0 )then str += " and " end + str += "#{key}='#{val}'" + count += 1 + } + return str + end + + def makeKeySet keys,record + str = "" + count = 0 + keys.each{|key| + val = record[key] + if( count>0 )then str += "," end + if( val.is_a?(String) )then + val2 = val.gsub("'","''") + val = val2 + #val = val2.gsub!("\"","\\\"") + end + str += "#{key}='#{val}'" + count += 1 + } + return str + end + + def makeInsertKeySet keys0,record + keyhash = Hash.new + keys0.each { |key| + keyhash[key]=1 + } + keys=Array.new + keyhash.each {|key,val| + keys.push( key ) + } + + keyset = "" + valset = "" + count = 0 + keys.each { |key| + if( count>0 )then + keyset += "," + valset += "," + end + keyset += key + if( record[key]==true )then #|| record[key]==false )then + valset += "1" + elsif( record[key]==false ) then + valset += "0" + else + if( record[key].is_a?(String) )then + val = record[key].gsub("'","''") + #val.gsub!("\"","\\\"") + valset += "'#{val}'" + else + valset += "'#{record[key]}'" + end + end + count += 1 + } + sql = "insert into #{tablename} (#{keyset}) values (#{valset})" + return sql + end + + def updateOrInsert recordKeys,conditionKeys,record + begin + #@debug_base=true + sql_update3 = makeKeyCondition( conditionKeys,record ) + puts "update or insert where cond = #{sql_update3} <== #{conditionKeys}" if @debug_base + records = @db.selectExec("select * from #{@tablename} where #{sql_update3}") + puts "HIT RECORDS=#{records}" if @debug_base + if( records!=nil && records.count>=1 ) + puts "record count = #{records.count}" if @debug_base + if( records.count>=1 )then + sql_update1 = "update #{tablename} set " + sql_update2 = makeKeySet( recordKeys,record ) + sql = "#{sql_update1}#{sql_update2} where #{sql_update3}" + p "updateOrInserti(udate) : #{sql}" if @debug_log + return @db.exec( sql ) + end + end + # array を合体?? + recordKeys2 = Marshal.load(Marshal.dump(recordKeys)) + recordKeys2.push( conditionKeys ) + recordKeys2.flatten! + sql = makeInsertKeySet( recordKeys2,record ) + p "updateOrInsert(insert) : #{sql}" if @debug_log + return @db.exec(sql) + rescue => e + puts "updateOrInsert Error : #{e}" + puts caller + end + end + + def get_unique_event_codes + sql = "SELECT DISTINCT event_code FROM #{@tablename}" + records = @db.selectExec(sql) + # Convert PG::Result to an array of hashes + return records.map { |row| row.to_h } + end +# http://libro.tuyano.com/index3?id=1102003&page=3 + + + def loadCSV host,username,projectid,f + i=0 + @fieldcount=0 + + tmpstr="" + tmpcount=0 + loop { + line0 = f.gets("\n") + if line0==nil then + break; + end + + # CSV 漢字変換対応 + begin + line = line0.gsub(/^\xEF\xBB\xBF/, '') + rescue + line = line0 + end + + line.chomp! + + puts "line=#{line}" + + if i==0 then + @title = line + #puts "First line:#{line}" + titleArray = line.split(",") + @fieldcount = titleArray.count() + #puts "Field count = #{@fieldcount}, #{@title}" + else + if tmpcount==0 then + #puts "Data : #{line}" + valuecsv="" + dataArray0 = line.split(",") + cnt=dataArray0.count() + dataArray=Array.new + dataArray0.each{ |dat| + if( dat=="" )then + dataArray.push(nil) + else + dataArray.push(dat) + end + } + if( cnt<@fieldcount )then + for i in cnt+1..@fieldcount do + dataArray.push(nil) + end + end + cnt=dataArray.count() + + tmpstr=line + else + valuecsv="" + tmpstr = "#{tmpstr}\n#{line}" + #puts "Data : #{tmpstr}" + dataArray0 = tmpstr.split(",") + cnt=dataArray0.count() + dataArray=Array.new + dataArray0.each{ |dat| + if( dat=="" )then + dataArray.push(nil) + else + dataArray.push(dat) + end + } + if( cnt<@fieldcount )then + for i in cnt+1..@fieldcount do + dataArray.push(nil) + end + end + cnt=dataArray.count() + end + #puts "---step 1----- count=#{cnt},fieldcount=#{@fieldcnt},tmpcount=#{tmpcount},title=#{@title},value=#{dataArray}" + if cnt==@fieldcount then + if tmpcount>0 then + tmpcount=0 + #puts "#{i} : #{tmpstr}" + tmpstr="" + end + num = 0 + numttl = 0 +# puts "---step 2-----" + loop{ + value = dataArray[num] + + if value!=nil then + firstchar = value[0,1] + lastchar = value[-1,1] + if firstchar=="\"" then + loop{ + if lastchar=="\"" then + break + else + num += 1 + valuenext=dataArray[num] + value = "#{value},#{valuenext}" + #puts ", #{valuenext}" + lastchar = value[-1,1] + end + } + end + #else + # value='' + end + +# puts "value = #{value}" + + #if value != nil then + # value = Iconv.iconv("utf-8", "windows-874", value).join + # value.gsub!("\'","\\\'") + #end + + if( value!=nil ) then + valuecsv = "#{valuecsv} '#{value}'" + else + valuecsv = "#{valuecsv} null" + end + num += 1 + numttl += 1 + if numttl >= @fieldcount then + break + end + valuecsv = "#{valuecsv}," +# puts "---step 3 (in loop)-----" + } + sql = "insert into #{@tablename} (#{@title}) values (#{valuecsv})" + #puts "SQL = #{sql}" + result = @db.exec(sql) + + puts "result=#{result}, sql=#{sql}}" + else + puts "Bad count : #{i} : current count=#{cnt}, target=#{@fieldcount}" + tmpcount = cnt + break + end + end + i += 1 + } + end + + def saveMongoCSVfromLocal host,username,projectid,csvfile + if( csvfile==nil ) then + puts "csvfile is null..." + return + end + + puts "loadCSV : file=#{csvfile}" + + #mongofile=UserMongoFileSystem.new + + mongofile=UserMongoFiles.new + mongodb = UserMongo.new + if host!=nil then + mongodb.connectMongo( host+'.mobilous.com',27017 ) + else + mongodb.connectMongo( 'localhost',27017 ) + end + db=mongodb.useDB("appexe") + + #mongofile.useCategory(db,"templates") + mongofile.useCategory(db,"database") + mongofile.insert(csvfile,projectid) + end + + def extractMongoCSVtoLocal host,username,projectid,csvfile + if( csvfile==nil ) then + puts "csvfile is null..." + return + end + + puts "loadCSV : file=#{csvfile}" + + mongofile=UserMongoFiles.new + mongodb = UserMongo.new + if host!=nil then + mongodb.connectMongo( host+'.mobilous.com',27017 ) + else + mongodb.connectMongo( 'localhost',27017 ) + end + db=mongodb.useDB("appexe") + #mongofile.useCategory(db,"templates") + mongofile.useCategory(db,"database") + f=mongofile.open(csvfile,projectid) + s = f.read() + + t=Tempfile.open("MobApp") + t.write(s) + + return t + #t.path + end + + def saveCSVintoTable host,username,projectid,localcsvfile + puts "csv=#{localcsvfile}" + + i=0; + aa= FasterCSV.table(localcsvfile,{ :headers => true,:quote_char => '"' }) + aa.each{ |row| + puts "row=#{i}" + row.each{ |value| + puts "val=#{value}" + } + i += 1 + } + end + + + + + + def loadCSVfromLocalFile host,username,projectid,csvfile + if( csvfile==nil ) then + puts "csvfile is null..." + return + end + + puts "loadCSV : file=#{csvfile}" + + #mongofile=UserMongoFileSystem.new + + mongofile=UserMongoFiles.new + mongodb = UserMongo.new + if( host!=nil ) then + hosturl=host+'.mobilous.com' + else + hosturl='localhost' + end + mongodb.connectMongo( hosturl,27017 ) + db=mongodb.useDB("appexe") + + #mongofile.useCategory(db,"templates") + mongofile.useCategory(db,"database") + mongofile.insert(csvfile,projectid) + + self.loadCSVfromMongo(host,username,projectid,csvfile) + end + + def loadCSVfromMongo host,username,projectid,csvfile + #puts "loadCSV is not implemented yet..." + + if( csvfile==nil ) then + puts "csvfile is null..." + return + end + + puts "loadCSV : file=#{csvfile}" + + mongofile=UserMongoFiles.new + mongodb = UserMongo.new + if( host !=nil )then + mongodb.connectMongo( host+'.mobilous.com',27017 ) + else + mongodb.connectMongo( 'localhost',27017 ) + end + db=mongodb.useDB("appexe") + #mongofile.useCategory(db,"templates") + mongofile.useCategory(db,"database") + f=mongofile.open(csvfile,projectid) + if( f!=nil )then + loadCSV(host,username,projectid,f) + end + end + +end + diff --git a/SumasenLibs/certificate_template.xlsx b/SumasenLibs/certificate_template.xlsx new file mode 100644 index 0000000..9b70a74 Binary files /dev/null and b/SumasenLibs/certificate_template.xlsx differ diff --git a/templates/activation-template.html b/templates/activation-template.html new file mode 100644 index 0000000..d278c2a --- /dev/null +++ b/templates/activation-template.html @@ -0,0 +1,32 @@ + + +
+ + +