Newer
Older
WhoMatch / system / app-tsuji.rb
@Sato fuma Sato fuma on 15 Dec 30 KB add
<!DOCTYPE html>
<html prefix="og: http://ogp.me/ns#" lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>2025-Tsuji/system/app.rb at master - HiroseLabo./2025-Tsuji</title>
    <meta property="og:title" content="2025-Tsuji/system/app.rb at master - HiroseLabo./2025-Tsuji" />
    <meta property="og:type" content="object" />
    <meta property="og:url" content="http://localhost:8880/HiroseLabo./2025-Tsuji/blob/master/system/app.rb" />
    
    
      <meta property="og:image" content="https://www.yatex.org/gitbucket/HiroseLabo./_avatar" />
      
    
    <link rel="icon" href="https://www.yatex.org/gitbucket/assets/common/images/gitbucket.png?20251213122956" type="image/vnd.microsoft.icon" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/google-fonts/css/source-sans-pro.css?20251213122956" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/bootstrap-3.4.1/css/bootstrap.min.css?20251213122956" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/octicons-4.4.0/octicons.min.css?20251213122956" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/bootstrap-datetimepicker-4.17.44/css/bootstrap-datetimepicker.min.css?20251213122956" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/colorpicker/css/bootstrap-colorpicker.min.css?20251213122956" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/color-themes-for-google-code-prettify/github-v2.min.css?20251213122956" type="text/css" rel="stylesheet"/>
    <link href="https://www.yatex.org/gitbucket/assets/vendors/facebox/facebox.css?20251213122956" rel="stylesheet"/>
    <link href="https://www.yatex.org/gitbucket/assets/vendors/AdminLTE-2.4.2/css/AdminLTE.min.css?20251213122956" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/AdminLTE-2.4.2/css/skins/skin-green-light.min.css?20251213122956" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/font-awesome-4.7.0/css/font-awesome.min.css?20251213122956" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/jquery-ui/jquery-ui.min.css?20251213122956" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/jquery-ui/jquery-ui.structure.min.css?20251213122956" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/jquery-ui/jquery-ui.theme.min.css?20251213122956" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/common/css/gitbucket.css?20251213122956" rel="stylesheet">
    <link href="https://www.yatex.org/gitbucket/assets/vendors/tipped/tipped.css?20251213122956" rel="stylesheet">
    <script src="https://www.yatex.org/gitbucket/assets/vendors/jquery/jquery-3.5.1.min.js?20251213122956"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/jquery-ui/jquery-ui.min.js?20251213122956"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/dropzone/dropzone.min.js?20251213122956"></script>
    <script src="https://www.yatex.org/gitbucket/assets/common/js/validation.js?20251213122956"></script>
    <script src="https://www.yatex.org/gitbucket/assets/common/js/gitbucket.js?20251213122956"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/bootstrap-3.4.1/js/bootstrap.min.js?20251213122956"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/bootstrap3-typeahead/bootstrap3-typeahead.min.js?20251213122956"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/bootstrap-datetimepicker-4.17.44/js/moment.min.js?20251213122956"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/bootstrap-datetimepicker-4.17.44/js/bootstrap-datetimepicker.min.js?20251213122956"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/colorpicker/js/bootstrap-colorpicker.min.js?20251213122956"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/google-code-prettify/prettify.js?20251213122956"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/elastic/jquery.elastic.source.js?20251213122956"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/facebox/facebox.js?20251213122956"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/jquery-hotkeys/jquery.hotkeys.js?20251213122956"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/jquery-textcomplete-1.8.4/jquery.textcomplete.min.js?20251213122956"></script>
    <script src="https://www.yatex.org/gitbucket/assets/vendors/tipped/tipped.min.js?20251213122956"></script>
    
      <meta name="go-import" content="www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji git https://www.yatex.org/gitbucket/git/HiroseLabo./2025-Tsuji.git" />
    
    <script src="https://www.yatex.org/gitbucket/assets/vendors/AdminLTE-2.4.2/js/adminlte.min.js?20251213122956" type="text/javascript"></script>
    
      <style type="text/css">.content, .sidebar, .skin-green-light div.main-sidebar {
  background:  #efe;
}</style>
    
  </head>
  <body class="skin-green-light page-load sidebar-mini ">
    <div class="wrapper">
      <header class="main-header">
        <a href="https://www.yatex.org/gitbucket/" class="logo">
          <span class="logo-mini"><img src="https://www.yatex.org/gitbucket/assets/common/images/gitbucket.svg?20251213122956" alt="GitBucket" /></span>
          <span class="logo-lg">
            <img src="https://www.yatex.org/gitbucket/assets/common/images/gitbucket.svg?20251213122956" alt="GitBucket" />
            <span class="header-title strong">GitBucket</span>
          </span>
        </a>
        <nav class="navbar navbar-static-top" role="navigation">
          <!-- Sidebar toggle button-->
          
            <a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button" title="Toggle navigation">
              <span class="sr-only">Toggle navigation</span>
            </a>
          
          
            <form id="search" action="https://www.yatex.org/gitbucket/search" method="GET" class="pc navbar-form navbar-left" role="search">
              <div class="form-group">
                <input type="text" name="query" id="navbar-search-input" class="form-control" placeholder="Find a repository" aria-label="Search"/>
              </div>
            </form>
            <ul class="pc nav navbar-nav">
              <li><a href="https://www.yatex.org/gitbucket/dashboard/pulls">Pull requests</a></li>
              <li><a href="https://www.yatex.org/gitbucket/dashboard/issues">Issues</a></li>
              
                
                  <li><a href="https://www.yatex.org/gitbucket/gist">Snippets</a></li>
                
              
            </ul>
          
          <div class="navbar-custom-menu">
            <ul class="nav navbar-nav">
              
                <li>
                  <a href="https://www.yatex.org/gitbucket/signin?redirect=%2FHiroseLabo.%2F2025-Tsuji%2Fblob%2Fmaster%2Fsystem%2Fapp.rb" class="pull-right" id="signin">Sign in</a>
                </li>
              
            </ul>
          </div>
        </nav>
      </header>
      
  


<div class="main-sidebar">
  <div class="sidebar">
    <ul class="sidebar-menu">
      
  <li class = "menu-item-hover active">
    
      <a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji">
        <i class="menu-icon octicon octicon-code"></i>
        <span>Files</span>
        
      </a>
    
  </li>

      
        
  <li class = "menu-item-hover ">
    
      <a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/branches">
        <i class="menu-icon octicon octicon-git-branch"></i>
        <span>Branches</span>
        
          <span class="pull-right-container"><span class="label label-primary pull-right">1</span></span>
        
      </a>
    
  </li>

      
      
  <li class = "menu-item-hover ">
    
      <a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/releases">
        <i class="menu-icon octicon octicon-tag"></i>
        <span>Releases</span>
        
      </a>
    
  </li>

      
        
  <li class = "menu-item-hover ">
    
      <a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/issues">
        <i class="menu-icon octicon octicon-issue-opened"></i>
        <span>Issues</span>
        
      </a>
    
  </li>

        
  <li class = "menu-item-hover ">
    
      <a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/pulls">
        <i class="menu-icon octicon octicon-git-pull-request"></i>
        <span>Pull requests</span>
        
      </a>
    
  </li>

        
  <li class = "menu-item-hover ">
    
      <a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/issues/labels">
        <i class="menu-icon octicon octicon-tag"></i>
        <span>Labels</span>
        
      </a>
    
  </li>

        
  <li class = "menu-item-hover ">
    
      <a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/issues/priorities">
        <i class="menu-icon octicon octicon-flame"></i>
        <span>Priorities</span>
        
      </a>
    
  </li>

        
  <li class = "menu-item-hover ">
    
      <a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/issues/milestones">
        <i class="menu-icon octicon octicon-milestone"></i>
        <span>Milestones</span>
        
      </a>
    
  </li>

      
      
        
  <li class = "menu-item-hover ">
    
      <a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/wiki">
        <i class="menu-icon octicon octicon-book"></i>
        <span>Wiki</span>
        
      </a>
    
  </li>

      
      
      
    </ul>
  </div>
</div>
<div class="content-wrapper">
  <div class="content body clearfix">
    <div class="headbar">
      <div class="container">
        

        
        <div class="head">
          <div class="pull-right">
            
              
            
            
              
                <a class="btn btn-default btn-sm" href="https://www.yatex.org/gitbucket/signin?redirect=https%3A%2F%2Fwww.yatex.org%2Fgitbucket%2FHiroseLabo.%2F2025-Tsuji">
                  <span class="strong"><i class="octicon octicon-repo-forked"></i>Fork</span><span class="muted">: 0</span>
                </a>
              
            
            <form id="fork-form" method="post" action="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/fork" style="display: none;">
              <input type="hidden" name="account" value=""/>
            </form>
          </div>
          
  
    <i class="mega-octicon octicon-repo"></i>
  


          <a href="https://www.yatex.org/gitbucket/HiroseLabo.">HiroseLabo.</a> / <a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji" class="strong">2025-Tsuji</a>

          
            
          
        </div>
      </div>
    </div>
    
    <style>
      .prettyprint {
        tab-size: 8
      }
    </style>
    <div class="head">
      <div class="pull-right hide-if-blame"><div class="btn-group">
        <a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/blob/b58ce336b872039f7e0caba06d28f263cd7af6b7/system/app.rb" data-hotkey="y" style="display: none;">Transfer to URL with SHA</a>
        <a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/find/master" class="btn btn-sm btn-default" data-hotkey="t">Find file</a>
      </div></div>
      <div class="line-age-legend">
        <span>Newer</span>
        <ol>
            <li class="heat1"></li>
            <li class="heat2"></li>
            <li class="heat3"></li>
            <li class="heat4"></li>
            <li class="heat5"></li>
            <li class="heat6"></li>
            <li class="heat7"></li>
            <li class="heat8"></li>
            <li class="heat9"></li>
            <li class="heat10"></li>
        </ol>
        <span>Older</span>
      </div>
      <div id="branchCtrlWrapper" style="display:inline;">
      
  <div class="btn-group" >
    <button class="dropdown-toggle btn btn-default btn-sm" data-toggle="dropdown">
      
        
          <span class="muted">branch:</span>
        
        <span class="strong"
              style="display:inline-block; vertical-align:bottom; overflow-x:hidden; max-width:200px; text-overflow:ellipsis">
          master
        </span>
      
      <span class="caret"></span>
    </button>
    <ul class="dropdown-menu">
      
      
  <li>
    <ul class="nav nav-tabs">
      <li class="active" id="branch-control-tab-branches"><a href="javascript:void(0);" class="nav-item" id="nav-item-branches">Branches</a></li>
      <li id="branch-control-tab-tags"><a href="javascript:void(0);" class="nav-item" id="nav-item-tags">Tags</a></li>
      <li><button id="branch-control-close" class="pull-right">&times</button></li>
    </ul>
    <li>
      <input id="branch-control-input" type="text" class="form-control input-sm dropdown-filter-input"/>
    </li>
    
        
          <li><a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/blob/master/system/app.rb">
  <i class="octicon octicon-check"></i>
 master</a></li>
        
      
    
  </li>

    </ul>
  </div>
  


<script>
  $(function(){
    $('#branch-control-input').parent().click(function(e) {
      e.stopPropagation();
    });

    $('#branch-control-close').click(function() {
      $('[data-toggle="dropdown"]').parent().removeClass('open');
    });

    $('#branch-control-input').keyup(function() {
      updateBranchControlListFilter();
    });

    

    $('.btn-group').click(function() {
      $('#branch-control-input').val('');
      //$('.dropdown-menu li').show();
      $('#create-branch').hide();
    });

    $('#nav-item-branches').click(function(e) {
      e.stopPropagation();
      updateBranchControlList('branches');
    });

    $('#nav-item-tags').click(function(e) {
      e.stopPropagation();
      updateBranchControlList('tags');
    });

    function updateBranchControlList(active) {
      if (active == 'branches') {
        $('li#branch-control-tab-branches').addClass('active');
        $('li#branch-control-tab-tags').removeClass('active');

        $('li.branch-control-item-branch').show();
        $('li.branch-control-item-branch > a').addClass('active');

        $('li.branch-control-item-tag').hide();
        $('li.branch-control-item-tag > a').removeClass('active');
        
          $('#branch-control-input').attr('placeholder', 'Find branch ...');
        
      } else if (active == 'tags') {
        $('li#branch-control-tab-branches').removeClass('active');
        $('li#branch-control-tab-tags').addClass('active');

        $('li.branch-control-item-branch').hide();
        $('li.branch-control-item-branch > a').removeClass('active');

        $('li.branch-control-item-tag').show();
        $('li.branch-control-item-tag > a').addClass('active');
        $('#branch-control-input').attr('placeholder', 'Find tag ...');
      }
      updateBranchControlListFilter();
    }

    function updateBranchControlListFilter() {
      const inputVal = $('#branch-control-input').val();
      $.each($('#branch-control-input').parent().parent().find('a.active').not('.nav-item'), function(index, elem) {
        if (!inputVal || !elem.text.trim() || elem.text.trim().toLowerCase().indexOf(inputVal.toLowerCase()) >= 0) {
          $(elem).parent().show();
        } else {
          $(elem).parent().hide();
        }
      });
      if ($('li#branch-control-tab-branches.active').length > 0) {
        
      }
    }

    // Initialize the branch control list
    updateBranchControlList('branches');
  });
</script>

      </div>
      <a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/tree/master">2025-Tsuji</a> /
      
        
          <a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/tree/master/system">system</a> /
        
      
        
          app.rb
        
      
      
    </div>
    <div class="box-header" style="line-height: 28px;">
      <a href="https://www.yatex.org/gitbucket/T-keita" class=""><img src="https://www.gravatar.com/avatar/5092dd69ff94eac90ec071b1df132981?s=20&d=retro&r=g" class="avatar-mini" style="width: 20px; height: 20px;"
     alt="@tsuji keita" /></a>
      <a href="https://www.yatex.org/gitbucket/T-keita" class="username strong">tsuji keita</a>
      <span class="muted">
  <span data-toggle="tooltip" title="2025-12-15 18:01:52">
    
      2 minutes ago
    
  </span>

</span>
      <span class="label label-default">5 KB</span>
      <a href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/commit/b58ce336b872039f7e0caba06d28f263cd7af6b7" class="commit-message">Add files via upload</a>
      <div class="btn-group pull-right">
        <a class="btn btn-sm btn-default" href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/raw/b58ce336b872039f7e0caba06d28f263cd7af6b7/system/app.rb">Raw</a>
        
          <a class="btn btn-sm btn-default blame-action" href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/blame/b58ce336b872039f7e0caba06d28f263cd7af6b7/system/app.rb"
            data-url="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/get-blame/b58ce336b872039f7e0caba06d28f263cd7af6b7/system/app.rb" data-repository="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji">Blame</a>
        
        <a class="btn btn-sm btn-default" href="https://www.yatex.org/gitbucket/HiroseLabo./2025-Tsuji/commits/master/system/app.rb">History</a>
        
        
      </div>
    </div>
    
      
        
          <div class="box-content-bottom">
            <pre class="prettyprint linenums blob  no-renderable  ">require &quot;sinatra&quot;
require &quot;sinatra/json&quot;
require &quot;sqlite3&quot;
require &quot;json&quot;
require &quot;securerandom&quot;
require &quot;bcrypt&quot;

set :bind, &#x27;0.0.0.0&#x27;
set :port, 9292
set :public_folder, File.join(__dir__, &quot;public&quot;)

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

# ✅ CORS(風馬さんのIPを明示)
before do
  response.headers[&quot;Access-Control-Allow-Origin&quot;] = &quot;http://172.20.16.218:4567&quot;
  response.headers[&quot;Access-Control-Allow-Credentials&quot;] = &quot;true&quot;
  response.headers[&quot;Access-Control-Allow-Headers&quot;] = &quot;Content-Type&quot;
end

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

# ✅ DB接続(風馬さんのDBに統一)
DB = SQLite3::Database.new &quot;database.db&quot;
DB.results_as_hash = true

# ✅ テーブル作成(風馬さん構成に統一)
DB.execute &lt;&lt;-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 &lt;&lt;-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 (&#x27;supporter&#x27;, &#x27;requester&#x27;)),
    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]
    halt 401, json(error: &quot;ログインしてください&quot;)
  end
end

# ✅ ユーザー登録(roleとinfo_levelを受け取る)
post &quot;/api/signup&quot; do
  content_type :json
  data = JSON.parse(request.body.read) rescue {}
  username = data[&quot;username&quot;]
  password = data[&quot;password&quot;]
  role     = data[&quot;role&quot;] || &quot;requester&quot;
  info_level = data[&quot;info_level&quot;] || 0.5

  halt 400, json(error: &quot;username, password, role が必要です&quot;) unless username &amp;&amp; password &amp;&amp; role

  password_hash = BCrypt::Password.create(password)

  begin
    DB.execute(&quot;INSERT INTO users (username, password_hash, role, info_level) VALUES (?, ?, ?, ?)&quot;,
               [username, password_hash, role, info_level])
    json(status: &quot;success&quot;, message: &quot;ユーザー登録成功&quot;, user: username, role: role)
  rescue SQLite3::ConstraintException
    halt 400, json(error: &quot;そのユーザー名は既に使われています&quot;)
  end
end

# ✅ ログイン
post &quot;/api/login&quot; do
  content_type :json
  data = JSON.parse(request.body.read) rescue {}
  username = data[&quot;username&quot;]
  password = data[&quot;password&quot;]

  halt 400, json(error: &quot;username and password required&quot;) unless username &amp;&amp; password

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

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

# ✅ ログアウト
post &quot;/api/logout&quot; do
  session.clear
  json(status: &quot;success&quot;, message: &quot;ログアウトしました&quot;)
end

# ✅ ログイン状態確認
get &quot;/api/me&quot; do
  require_login
  user = DB.execute(&quot;SELECT id, username, role, trust_score, info_level FROM users WHERE id = ?&quot;, [session[:user_id]]).first
  json user
end

# ✅ 依頼送信
post &quot;/api/requests&quot; do
  require_login
  content_type :json
  data = JSON.parse(request.body.read) rescue {}

  category    = data[&quot;category&quot;]
  description = data[&quot;description&quot;] || &quot;依頼内容&quot;
  latitude    = data[&quot;latitude&quot;] || 38.9
  longitude   = data[&quot;longitude&quot;] || 139.8
  start_time  = data[&quot;start_time&quot;] || Time.now.strftime(&quot;%Y-%m-%d %H:%M&quot;)
  end_time    = data[&quot;end_time&quot;]
  info_level  = data[&quot;info_level&quot;] || 0.5

  halt 400, json(error: &quot;category required&quot;) unless category

  DB.execute(&quot;INSERT INTO requests (category, description, latitude, longitude, start_time, end_time, info_level)
              VALUES (?, ?, ?, ?, ?, ?, ?)&quot;,
              [category, description, latitude, longitude, start_time, end_time, info_level])
  id = DB.last_insert_row_id

  json(
    id: id,
    category: category,
    description: description,
    latitude: latitude,
    longitude: longitude,
    start_time: start_time,
    info_level: info_level
  )
end

# ✅ 依頼一覧取得
get &quot;/api/requests&quot; do
  require_login
  content_type :json
  rows = DB.execute(&quot;SELECT * FROM requests ORDER BY id DESC&quot;)
  json rows
end

# ✅ フロント配信
get &quot;/&quot; do
  send_file File.join(settings.public_folder, &quot;index.html&quot;)
end

</pre>
          </div>
        
        
        
      
    
  
  </div>
</div>
<script>
$(function(){
  $('a[rel*=facebox]').facebox({
    'loadingImage': 'https://www.yatex.org/gitbucket/assets/vendors/facebox/loading.gif?20251213122956',
    'closeImage': 'https://www.yatex.org/gitbucket/assets/vendors/facebox/closelabel.png?20251213122956'
  });

  $(document).on("click", ".js-fork-owner-select-target", function() {
    var account = $(this).text().replace("@", "");
    $("#account").val(account);
    $("#fork").submit();
  });
});
</script>




    </div>
    <script>
      $(function(){
        
        
          $(".sidebar-toggle").on('click', function(e){
            $.post('https://www.yatex.org/gitbucket/sidebar-collapse', { collapse: !$('body').hasClass('sidebar-collapse') });
          });
        
      });
    </script>
    
    
      <script>
        $('head').append($('<link rel="stylesheet" type="text/css" href="https://www.yatex.org/gitbucket/user.css">'))
      </script>
    
  </body>
</html>

<script>
$(window).on('load', function(){
  window.onhashchange = function(){
    updateHighlighting();
  }

  const pre = $('pre.prettyprint');
  function updateSourceLineNum() {
    $('.source-line-num').remove();
    const pos = pre.find('ol.linenums').position();
    if (pos) {
      $('<div class="source-line-num">').css({
        height  : pre.height(),
        width   : '48px',
        cursor  : 'pointer',
        position: 'absolute',
        top     : pos.top + 'px',
        left    : pos.left + 'px'
      }).click(function(e){
        let pos = $(this).data("pos");
        if (!pos) {
          pos = $('ol.linenums li').map(function(){ return { id: $(this).attr("id"), top: $(this).position().top} }).toArray();
          $(this).data("pos",pos);
        }
        let i = 0;
        for(i = 0; i < pos.length - 1; i++){
          if(pos[i + 1].top > e.pageY){
            break;
          }
        }
        const line    = pos[i].id.replace(/^L/,'');
        const hash    = location.hash;
        const baseUrl = location.toString().split("#")[0];
        if (e.shiftKey == true && hash.match(/#L\d+(-L\d+)?/)) {
          const fragments = hash.split('-');
          window.history.pushState('', '', baseUrl + fragments[0] + '-L' + line);
        } else {
          const p = $("#L" + line).attr('id', '');
          window.history.pushState('', '', baseUrl + '#L' + line);
          p.attr('id','L' + line);
        }
        $("#branchCtrlWrapper .btn .muted").text("tree:");
        $("#branchCtrlWrapper .btn .strong").text("b58ce336b8");
        getSelection().empty();
        updateHighlighting();
      }).appendTo(pre);
      updateHighlighting();
    } else {
      // Maybe code view is not initialized yet. Retry until succeed.
      setTimeout(updateSourceLineNum, 300);
    }
  }
  const repository = $('.blame-action').data('repository');
  $('.blame-action').click(function(e){
    if(history.pushState && $('pre.prettyprint.no-renderable').length){
      e.preventDefault();
      history.pushState(null, null, this.href);
      updateBlame();
    }
  });

  function updateBlame(){
    const m = /\/(blame|blob)(\/.*)$/.exec(location.href);
    const mode = m[1];
    $('.blame-action').toggleClass("active", mode=='blame').attr('href', repository + (m[1] == 'blame' ? '/blob' : '/blame') + m[2]);
    if(pre.parents("div.box-content-bottom").find(".blame").length){
      pre.parent().toggleClass("blame-container", mode == 'blame');
      updateSourceLineNum();
      return;
    }
    if(mode == 'blob'){
      updateSourceLineNum();
      return;
    }
    $(document.body).toggleClass('no-box-shadow', document.body.style.boxShadow === undefined);
    $('.blame-action').addClass("active");
    const base = $('<div class="blame">').css({height: pre.height()}).prependTo(pre.parents("div.box-content-bottom"));
    base.parent().addClass("blame-container");
    updateSourceLineNum();
    $.get($('.blame-action').data('url')).done(function(data){
      let blame = data.blame;
      let lastDiv;
      const now = new Date().getTime();
      const index = [];
      for(let i = 0; i < blame.length; i++){
        for(let j = 0; j < blame[i].lines.length; j++){
          index[blame[i].lines[j]] = blame[i];
        }
      }

      $('pre.prettyprint ol.linenums li').each(function(i, e){
        const p = $(e).position();
        const h = $(e).height();
        if(blame == index[i]){
          lastDiv.css("min-height",(p.top + h + 1) - lastDiv.position().top);
        } else {
          $(e).addClass('blame-sep')
          blame = index[i];
          const sha = $('<div class="blame-sha">')
             .append($('<a>').attr("href", data.root + '/commit/' + blame.id).text(blame.id.substr(0, 7)));
          if (blame.prev) {
             sha.append($('<br />'))
             .append($('<a class="muted-link">').text('prev').attr("href", data.root + '/blame/' + blame.prev + '/' + (blame.prevPath || data.path)));
          }
          lastDiv = $('<div class="blame-info">')
           .addClass('heat' + Math.min(10, Math.max(1, Math.ceil((now - blame.commited) / (24 * 3600 * 1000 * 70)))))
           .toggleClass('blame-last', blame.id == data.last)
           .data('line', (i + 1))
           .css({
             "top"        : p.top + 'px',
             "min-height" : h + 'px'
           })
           .append(sha)
           .append($(blame.avatar).addClass('avatar').css({"float": "left"}))
           .append($('<div class="blame-commit-title">').text(blame.message))
           .append($('<div class="muted">').html(blame.author + " authed " + blame.authed))
           .appendTo(base);
        }
      });
    });
    return false;
  };

  $(document).on('expanded.pushMenu collapsed.pushMenu', function(e){
    setTimeout(updateBlame, 300);
  });

  updateBlame();
});

let scrolling = false;

/**
 * Highlight lines which are specified by URL hash.
 */
function updateHighlighting() {
  const hash = location.hash;
  const isDark = false;
  if (hash.match(/#L\d+(-L\d+)?/)) {
    if (isDark) {
      $('li.highlight-dark').removeClass('highlight-dark');
    } else {
      $('li.highlight').removeClass('highlight');
    }
    const fragments = hash.substr(1).split('-');
    if (fragments.length == 1) {
      if (isDark) {
        $('#' + fragments[0]).addClass('highlight-dark');
      } else {
        $('#' + fragments[0]).addClass('highlight');
      }
      if(!scrolling){
        $(window).scrollTop($('#' + fragments[0]).offset().top);
      }
    } else if(fragments.length > 1){
      const start = parseInt(fragments[0].substr(1));
      const end   = parseInt(fragments[1].substr(1));
      for (let i = start; i <= end; i++) {
        if (isDark) {
          $('#L' + i).addClass('highlight-dark');
        } else {
          $('#L' + i).addClass('highlight');
        }
      }
      if (!scrolling) {
        $(window).scrollTop($('#' + fragments[0]).offset().top);
      }
    }
  }
  scrolling = true;
}
</script>