Newer
Older
WhoMatch / system / app.rb
@Sato fuma Sato fuma on 15 Dec 4 KB add
require 'sinatra'
require 'sinatra/json'
require 'sqlite3'
require 'bcrypt'
require 'erb'
require 'securerandom'

set :bind, '0.0.0.0'
set :port, 4567

# ✅ セッション設定
use Rack::Session::Cookie,
  key: 'rack.session',
  path: '/',
  same_site: :lax,
  secure: false,
  secret: SecureRandom.hex(64)

# ✅ CORS(Cookie を許可)
before do
  response.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:4567'
  response.headers['Access-Control-Allow-Credentials'] = 'true'
end

options '*' do
  response.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:4567'
  response.headers['Access-Control-Allow-Credentials'] = 'true'
  response.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
  response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
  200
end

# ✅ DB
DB = SQLite3::Database.new "database.db"
DB.results_as_hash = true

DB.execute <<-SQL
  CREATE TABLE IF NOT EXISTS requests (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    category TEXT NOT NULL,
    description TEXT,
    latitude REAL NOT NULL,
    longitude REAL NOT NULL,
    start_time TEXT,
    end_time TEXT,
    info_level REAL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
  );
SQL

DB.execute <<-SQL
  CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    username TEXT UNIQUE NOT NULL,
    password_hash TEXT NOT NULL,
    role TEXT NOT NULL CHECK(role IN ('supporter', 'requester')),
    trust_score REAL DEFAULT 0.5,
    info_level REAL DEFAULT 0.5,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
  );
SQL

# ✅ ログイン必須
def require_login
  unless session[:user_id]
    if request.path.start_with?("/api/")
      halt 401, json({ error: "ログインが必要です" })
    else
      redirect '/login'
    end
  end
end

# ✅ signup
post '/api/signup' do
  data = JSON.parse(request.body.read)
  username = data["username"]
  password = data["password"]
  role     = data["role"] || "requester"
  info_level = data["info_level"] || 0.5

  halt 400, json({ error: "username, password, role が必要です" }) if username.nil? || password.nil? || role.nil?

  password_hash = BCrypt::Password.create(password)

  begin
    DB.execute("INSERT INTO users (username, password_hash, role, info_level) VALUES (?, ?, ?, ?)",
               [username, password_hash, role, info_level])
  rescue SQLite3::ConstraintException
    halt 400, json({ error: "そのユーザー名は既に使われています" })
  end

  json({ status: "success", message: "ユーザー登録完了", role: role })
end

# ✅ login
post '/api/login' do
  data = JSON.parse(request.body.read)
  username = data["username"]
  password = data["password"]

  user = DB.execute("SELECT * FROM users WHERE username = ?", [username]).first
  halt 401, json({ error: "ユーザーが存在しません" }) unless user

  if BCrypt::Password.new(user["password_hash"]) == password
    session[:user_id] = user["id"]
    json({
      status: "success",
      message: "ログイン成功",
      user: user["username"],
      role: user["role"],
      trust_score: user["trust_score"],
      info_level: user["info_level"]
    })
  else
    halt 401, json({ error: "パスワードが違います" })
  end
end

# ✅ logout
post '/api/logout' do
  session.clear
  json({ status: "success", message: "ログアウトしました" })
end

# ✅ me
get '/api/me' do
  require_login
  user = DB.execute("SELECT id, username, role, trust_score, info_level FROM users WHERE id = ?", [session[:user_id]]).first
  json user
end

# ✅ トップページ
get '/' do
  require_login
  @requests = DB.execute("SELECT * FROM requests")
  erb :index
end

get '/signup' do
  erb :signup
end

get '/login' do
  erb :login
end

# ✅ 依頼一覧
get '/api/requests' do
  require_login
  rows = DB.execute("SELECT * FROM requests")
  json rows
end

# ✅ 依頼登録
post '/api/requests' do
  require_login

  data = JSON.parse(request.body.read)

  category    = data["category"]
  description = data["description"]
  latitude    = data["latitude"]
  longitude   = data["longitude"]
  start_time  = data["start_time"]
  end_time    = data["end_time"]
  info_level  = data["info_level"] || 0.5

  if category.nil? || latitude.nil? || longitude.nil?
    halt 400, json({ error: "必須項目が不足しています" })
  end

  DB.execute(
    "INSERT INTO requests (category, description, latitude, longitude, start_time, end_time, info_level)
     VALUES (?, ?, ?, ?, ?, ?, ?)",
    [category, description, latitude, longitude, start_time, end_time, info_level]
  )

  json({ status: "success", message: "依頼を登録しました" })
end