diff --git a/Gemfile b/Gemfile index 3d5bd275..4001fa71 100644 --- a/Gemfile +++ b/Gemfile @@ -65,4 +65,4 @@ gem 'kaminari' gem 'ransack' gem 'bootstrap' gem 'dartsass-sprockets' - +gem "rswag-ui" diff --git a/Gemfile.lock b/Gemfile.lock index 6fccfb14..2b48bb68 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,29 +9,29 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (7.2.2.1) - actionpack (= 7.2.2.1) - activesupport (= 7.2.2.1) + actioncable (7.2.2.2) + actionpack (= 7.2.2.2) + activesupport (= 7.2.2.2) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.2.2.1) - actionpack (= 7.2.2.1) - activejob (= 7.2.2.1) - activerecord (= 7.2.2.1) - activestorage (= 7.2.2.1) - activesupport (= 7.2.2.1) + actionmailbox (7.2.2.2) + actionpack (= 7.2.2.2) + activejob (= 7.2.2.2) + activerecord (= 7.2.2.2) + activestorage (= 7.2.2.2) + activesupport (= 7.2.2.2) mail (>= 2.8.0) - actionmailer (7.2.2.1) - actionpack (= 7.2.2.1) - actionview (= 7.2.2.1) - activejob (= 7.2.2.1) - activesupport (= 7.2.2.1) + actionmailer (7.2.2.2) + actionpack (= 7.2.2.2) + actionview (= 7.2.2.2) + activejob (= 7.2.2.2) + activesupport (= 7.2.2.2) mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.2.2.1) - actionview (= 7.2.2.1) - activesupport (= 7.2.2.1) + actionpack (7.2.2.2) + actionview (= 7.2.2.2) + activesupport (= 7.2.2.2) nokogiri (>= 1.8.5) racc rack (>= 2.2.4, < 3.2) @@ -40,35 +40,35 @@ GEM rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) useragent (~> 0.16) - actiontext (7.2.2.1) - actionpack (= 7.2.2.1) - activerecord (= 7.2.2.1) - activestorage (= 7.2.2.1) - activesupport (= 7.2.2.1) + actiontext (7.2.2.2) + actionpack (= 7.2.2.2) + activerecord (= 7.2.2.2) + activestorage (= 7.2.2.2) + activesupport (= 7.2.2.2) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.2.2.1) - activesupport (= 7.2.2.1) + actionview (7.2.2.2) + activesupport (= 7.2.2.2) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (7.2.2.1) - activesupport (= 7.2.2.1) + activejob (7.2.2.2) + activesupport (= 7.2.2.2) globalid (>= 0.3.6) - activemodel (7.2.2.1) - activesupport (= 7.2.2.1) - activerecord (7.2.2.1) - activemodel (= 7.2.2.1) - activesupport (= 7.2.2.1) + activemodel (7.2.2.2) + activesupport (= 7.2.2.2) + activerecord (7.2.2.2) + activemodel (= 7.2.2.2) + activesupport (= 7.2.2.2) timeout (>= 0.4.0) - activestorage (7.2.2.1) - actionpack (= 7.2.2.1) - activejob (= 7.2.2.1) - activerecord (= 7.2.2.1) - activesupport (= 7.2.2.1) + activestorage (7.2.2.2) + actionpack (= 7.2.2.2) + activejob (= 7.2.2.2) + activerecord (= 7.2.2.2) + activesupport (= 7.2.2.2) marcel (~> 1.0) - activesupport (7.2.2.1) + activesupport (7.2.2.2) base64 benchmark (>= 0.3) bigdecimal @@ -83,16 +83,16 @@ GEM addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) ast (2.4.3) - base64 (0.2.0) + base64 (0.3.0) bcrypt (3.1.20) - benchmark (0.4.0) - bigdecimal (3.1.9) + benchmark (0.5.0) + bigdecimal (3.3.1) bindex (0.8.1) - bootsnap (1.18.4) + bootsnap (1.18.6) msgpack (~> 1.2) bootstrap (5.3.5) popper_js (>= 2.11.8, < 3) - brakeman (7.0.2) + brakeman (7.1.0) racc builder (3.3.0) capybara (3.40.0) @@ -105,7 +105,7 @@ GEM regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) concurrent-ruby (1.3.5) - connection_pool (2.5.3) + connection_pool (2.5.4) crass (1.0.6) dartsass-sprockets (3.2.1) railties (>= 4.0.0) @@ -114,40 +114,44 @@ GEM sprockets-rails tilt date (3.4.1) - debug (1.10.0) + debug (1.11.0) irb (~> 1.10) reline (>= 0.3.8) dotenv (3.1.8) dotenv-rails (3.1.8) dotenv (= 3.1.8) railties (>= 6.1) - drb (2.2.1) + drb (2.2.3) + erb (5.1.1) erubi (1.13.1) - faraday (2.13.1) + faraday (2.14.0) faraday-net_http (>= 2.0, < 3.5) json logger - faraday-net_http (3.4.0) + faraday-net_http (3.4.1) net-http (>= 0.5.0) gemoji (4.1.0) - globalid (1.2.1) + globalid (1.3.0) activesupport (>= 6.1) - google-protobuf (4.30.2) + google-protobuf (4.33.0) bigdecimal rake (>= 13) - google-protobuf (4.30.2-aarch64-linux) + google-protobuf (4.33.0-aarch64-linux-gnu) bigdecimal rake (>= 13) - google-protobuf (4.30.2-arm64-darwin) + google-protobuf (4.33.0-aarch64-linux-musl) bigdecimal rake (>= 13) - google-protobuf (4.30.2-x86-linux) + google-protobuf (4.33.0-arm64-darwin) bigdecimal rake (>= 13) - google-protobuf (4.30.2-x86_64-darwin) + google-protobuf (4.33.0-x86_64-darwin) bigdecimal rake (>= 13) - google-protobuf (4.30.2-x86_64-linux) + google-protobuf (4.33.0-x86_64-linux-gnu) + bigdecimal + rake (>= 13) + google-protobuf (4.33.0-x86_64-linux-musl) bigdecimal rake (>= 13) hashie (5.0.0) @@ -156,11 +160,11 @@ GEM nokogiri (>= 1.4) i18n (1.14.7) concurrent-ruby (~> 1.0) - importmap-rails (2.1.0) + importmap-rails (2.2.2) actionpack (>= 6.0.0) activesupport (>= 6.0.0) railties (>= 6.0.0) - io-console (0.8.0) + io-console (0.8.1) irb (1.15.2) pp (>= 0.6.0) rdoc (>= 4.0.0) @@ -174,11 +178,11 @@ GEM rinku rouge sanitize - jbuilder (2.13.0) - actionview (>= 5.0.0) - activesupport (>= 5.0.0) - json (2.11.3) - jwt (2.10.1) + jbuilder (2.14.1) + actionview (>= 7.0.0) + activesupport (>= 7.0.0) + json (2.15.2) + jwt (3.1.2) base64 kaminari (1.2.2) activesupport (>= 4.1.0) @@ -196,28 +200,28 @@ GEM rexml (>= 3.3.9) kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) - language_server-protocol (3.17.0.4) + language_server-protocol (3.17.0.5) lint_roller (1.1.0) logger (1.7.0) - loofah (2.24.0) + loofah (2.24.1) crass (~> 1.0.2) nokogiri (>= 1.12.0) - mail (2.8.1) + mail (2.9.0) + logger mini_mime (>= 0.1.1) net-imap net-pop net-smtp - marcel (1.0.4) - matrix (0.4.2) + marcel (1.1.0) + matrix (0.4.3) mini_mime (1.1.5) - mini_portile2 (2.8.8) - minitest (5.25.5) + minitest (5.26.0) msgpack (1.8.0) multi_xml (0.7.2) bigdecimal (~> 3.1) net-http (0.6.0) uri - net-imap (0.5.8) + net-imap (0.5.12) date net-protocol net-pop (0.1.2) @@ -227,34 +231,33 @@ GEM net-smtp (0.5.1) net-protocol nio4r (2.7.4) - nokogiri (1.18.8) - mini_portile2 (~> 2.8.2) - racc (~> 1.4) - nokogiri (1.18.8-aarch64-linux-gnu) + nokogiri (1.18.10-aarch64-linux-gnu) racc (~> 1.4) - nokogiri (1.18.8-aarch64-linux-musl) + nokogiri (1.18.10-aarch64-linux-musl) racc (~> 1.4) - nokogiri (1.18.8-arm-linux-gnu) + nokogiri (1.18.10-arm-linux-gnu) racc (~> 1.4) - nokogiri (1.18.8-arm-linux-musl) + nokogiri (1.18.10-arm-linux-musl) racc (~> 1.4) - nokogiri (1.18.8-arm64-darwin) + nokogiri (1.18.10-arm64-darwin) racc (~> 1.4) - nokogiri (1.18.8-x86_64-darwin) + nokogiri (1.18.10-x86_64-darwin) racc (~> 1.4) - nokogiri (1.18.8-x86_64-linux-gnu) + nokogiri (1.18.10-x86_64-linux-gnu) racc (~> 1.4) - nokogiri (1.18.8-x86_64-linux-musl) + nokogiri (1.18.10-x86_64-linux-musl) racc (~> 1.4) - oauth2 (2.0.9) - faraday (>= 0.17.3, < 3.0) - jwt (>= 1.0, < 3.0) + oauth2 (2.0.17) + faraday (>= 0.17.3, < 4.0) + jwt (>= 1.0, < 4.0) + logger (~> 1.2) multi_xml (~> 0.5) rack (>= 1.2, < 4) - snaky_hash (~> 2.0) - version_gem (~> 1.1) - omniauth (2.1.3) + snaky_hash (~> 2.0, >= 2.0.3) + version_gem (~> 1.1, >= 1.1.9) + omniauth (2.1.4) hashie (>= 3.4.6) + logger rack (>= 2.2.3) rack-protection omniauth-github-team-member (2.1.0) @@ -266,23 +269,23 @@ GEM actionpack (>= 4.2) omniauth (~> 2.0) parallel (1.27.0) - parser (3.3.8.0) + parser (3.3.10.0) ast (~> 2.4.1) racc popper_js (2.11.8) - pp (0.6.2) + pp (0.6.3) prettyprint prettyprint (0.2.0) - prism (1.4.0) - psych (5.2.5) + prism (1.6.0) + psych (5.2.6) date stringio public_suffix (6.0.2) - puma (6.6.0) + puma (7.1.0) nio4r (~> 2.0) racc (1.8.1) - rack (3.1.14) - rack-protection (4.1.1) + rack (3.1.18) + rack-protection (4.2.1) base64 (>= 0.1.0) logger (>= 1.6.0) rack (>= 3.0.0, < 4) @@ -293,50 +296,55 @@ GEM rack (>= 1.3) rackup (2.2.1) rack (>= 3) - rails (7.2.2.1) - actioncable (= 7.2.2.1) - actionmailbox (= 7.2.2.1) - actionmailer (= 7.2.2.1) - actionpack (= 7.2.2.1) - actiontext (= 7.2.2.1) - actionview (= 7.2.2.1) - activejob (= 7.2.2.1) - activemodel (= 7.2.2.1) - activerecord (= 7.2.2.1) - activestorage (= 7.2.2.1) - activesupport (= 7.2.2.1) + rails (7.2.2.2) + actioncable (= 7.2.2.2) + actionmailbox (= 7.2.2.2) + actionmailer (= 7.2.2.2) + actionpack (= 7.2.2.2) + actiontext (= 7.2.2.2) + actionview (= 7.2.2.2) + activejob (= 7.2.2.2) + activemodel (= 7.2.2.2) + activerecord (= 7.2.2.2) + activestorage (= 7.2.2.2) + activesupport (= 7.2.2.2) bundler (>= 1.15.0) - railties (= 7.2.2.1) - rails-dom-testing (2.2.0) + railties (= 7.2.2.2) + rails-dom-testing (2.3.0) activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) rails-html-sanitizer (1.6.2) loofah (~> 2.21) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) - railties (7.2.2.1) - actionpack (= 7.2.2.1) - activesupport (= 7.2.2.1) + railties (7.2.2.2) + actionpack (= 7.2.2.2) + activesupport (= 7.2.2.2) irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) zeitwerk (~> 2.6) rainbow (3.1.1) - rake (13.2.1) - ransack (4.3.0) - activerecord (>= 6.1.5) - activesupport (>= 6.1.5) + rake (13.3.0) + ransack (4.4.1) + activerecord (>= 7.2) + activesupport (>= 7.2) i18n - rdoc (6.13.1) + rdoc (6.15.0) + erb psych (>= 4.0.0) - regexp_parser (2.10.0) - reline (0.6.1) + tsort + regexp_parser (2.11.3) + reline (0.6.2) io-console (~> 0.5) - rexml (3.4.1) + rexml (3.4.4) rinku (2.0.6) - rouge (4.5.2) - rubocop (1.75.5) + rouge (4.6.1) + rswag-ui (2.16.0) + actionpack (>= 5.2, < 8.1) + railties (>= 5.2, < 8.1) + rubocop (1.81.6) json (~> 2.3) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.1.0) @@ -344,62 +352,59 @@ GEM parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 2.9.3, < 3.0) - rubocop-ast (>= 1.44.0, < 2.0) + rubocop-ast (>= 1.47.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 4.0) - rubocop-ast (1.44.1) + rubocop-ast (1.47.1) parser (>= 3.3.7.2) prism (~> 1.4) - rubocop-performance (1.25.0) + rubocop-performance (1.26.1) lint_roller (~> 1.1) rubocop (>= 1.75.0, < 2.0) - rubocop-ast (>= 1.38.0, < 2.0) - rubocop-rails (2.31.0) + rubocop-ast (>= 1.47.1, < 2.0) + rubocop-rails (2.33.4) activesupport (>= 4.2.0) lint_roller (~> 1.1) rack (>= 1.1) rubocop (>= 1.75.0, < 2.0) - rubocop-ast (>= 1.38.0, < 2.0) + rubocop-ast (>= 1.44.0, < 2.0) rubocop-rails-omakase (1.1.0) rubocop (>= 1.72) rubocop-performance (>= 1.24) rubocop-rails (>= 2.30) ruby-progressbar (1.13.0) - rubyzip (2.3.2) + rubyzip (3.2.1) sanitize (7.0.0) crass (~> 1.0.2) nokogiri (>= 1.16.8) - sass-embedded (1.88.0) - google-protobuf (~> 4.30) - rake (>= 13) - sass-embedded (1.88.0-aarch64-linux-gnu) - google-protobuf (~> 4.30) - sass-embedded (1.88.0-aarch64-linux-musl) - google-protobuf (~> 4.30) - sass-embedded (1.88.0-arm-linux-gnueabihf) - google-protobuf (~> 4.30) - sass-embedded (1.88.0-arm-linux-musleabihf) - google-protobuf (~> 4.30) - sass-embedded (1.88.0-arm64-darwin) - google-protobuf (~> 4.30) - sass-embedded (1.88.0-x86_64-darwin) - google-protobuf (~> 4.30) - sass-embedded (1.88.0-x86_64-linux-gnu) - google-protobuf (~> 4.30) - sass-embedded (1.88.0-x86_64-linux-musl) - google-protobuf (~> 4.30) - sassc-embedded (1.80.4) + sass-embedded (1.93.2-aarch64-linux-gnu) + google-protobuf (~> 4.31) + sass-embedded (1.93.2-aarch64-linux-musl) + google-protobuf (~> 4.31) + sass-embedded (1.93.2-arm-linux-gnueabihf) + google-protobuf (~> 4.31) + sass-embedded (1.93.2-arm-linux-musleabihf) + google-protobuf (~> 4.31) + sass-embedded (1.93.2-arm64-darwin) + google-protobuf (~> 4.31) + sass-embedded (1.93.2-x86_64-darwin) + google-protobuf (~> 4.31) + sass-embedded (1.93.2-x86_64-linux-gnu) + google-protobuf (~> 4.31) + sass-embedded (1.93.2-x86_64-linux-musl) + google-protobuf (~> 4.31) + sassc-embedded (1.80.5) sass-embedded (~> 1.80) securerandom (0.4.1) - selenium-webdriver (4.32.0) + selenium-webdriver (4.38.0) base64 (~> 0.2) logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) - rubyzip (>= 1.2.2, < 3.0) + rubyzip (>= 1.2.2, < 4.0) websocket (~> 1.0) - snaky_hash (2.0.1) - hashie - version_gem (~> 1.1, >= 1.1.1) + snaky_hash (2.0.3) + hashie (>= 0.1.0, < 6) + version_gem (>= 1.1.8, < 3) sprockets (4.2.2) concurrent-ruby (~> 1.0) logger @@ -408,58 +413,54 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) - sqlite3 (2.6.0-aarch64-linux-gnu) - sqlite3 (2.6.0-aarch64-linux-musl) - sqlite3 (2.6.0-arm-linux-gnu) - sqlite3 (2.6.0-arm-linux-musl) - sqlite3 (2.6.0-arm64-darwin) - sqlite3 (2.6.0-x86-linux-gnu) - sqlite3 (2.6.0-x86-linux-musl) - sqlite3 (2.6.0-x86_64-darwin) - sqlite3 (2.6.0-x86_64-linux-gnu) - sqlite3 (2.6.0-x86_64-linux-musl) + sqlite3 (2.7.4-aarch64-linux-gnu) + sqlite3 (2.7.4-aarch64-linux-musl) + sqlite3 (2.7.4-arm-linux-gnu) + sqlite3 (2.7.4-arm-linux-musl) + sqlite3 (2.7.4-arm64-darwin) + sqlite3 (2.7.4-x86_64-darwin) + sqlite3 (2.7.4-x86_64-linux-gnu) + sqlite3 (2.7.4-x86_64-linux-musl) stimulus-rails (1.3.4) railties (>= 6.0.0) stringio (3.1.7) - thor (1.3.2) - tilt (2.6.0) + thor (1.4.0) + tilt (2.6.1) timeout (0.4.3) - turbo-rails (2.0.13) + tsort (0.2.0) + turbo-rails (2.0.17) actionpack (>= 7.1.0) railties (>= 7.1.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - unicode-display_width (3.1.4) - unicode-emoji (~> 4.0, >= 4.0.4) - unicode-emoji (4.0.4) - uri (1.0.3) + unicode-display_width (3.2.0) + unicode-emoji (~> 4.1) + unicode-emoji (4.1.0) + uri (1.0.4) useragent (0.16.11) - version_gem (1.1.8) + version_gem (1.1.9) web-console (4.2.1) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) websocket (1.2.11) - websocket-driver (0.7.7) + websocket-driver (0.8.0) base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.7.2) + zeitwerk (2.7.3) PLATFORMS - aarch64-linux aarch64-linux-gnu aarch64-linux-musl - arm-linux arm-linux-gnu + arm-linux-gnueabihf arm-linux-musl + arm-linux-musleabihf arm64-darwin - x86-linux - x86-linux-gnu - x86-linux-musl x86_64-darwin x86_64-linux-gnu x86_64-linux-musl @@ -484,6 +485,7 @@ DEPENDENCIES puma (>= 5.0) rails (~> 7.2.2) ransack + rswag-ui rubocop-rails-omakase selenium-webdriver sprockets-rails diff --git a/app/controllers/api_tokens_controller.rb b/app/controllers/api_tokens_controller.rb index d66aac4f..b0f76cce 100644 --- a/app/controllers/api_tokens_controller.rb +++ b/app/controllers/api_tokens_controller.rb @@ -2,6 +2,8 @@ class ApiTokensController < ApplicationController before_action :set_api_token, only: %i[ show edit update destroy ] + before_action :correct_user, only: %i[ show edit update destroy ] + # GET /api_tokens or /api_tokens.json def index @@ -69,4 +71,14 @@ def set_api_token def api_token_params params.require(:api_token).permit(:secret, :description, :expired_at, :user_id) end + + # Check if the logged in user is the owner of the api_token + def correct_user + if ! current_user?(@api_token.user) + respond_to do |format| + format.html { redirect_to api_tokens_url } + format.json { render status: :not_found, json: { status: 404, message: 'Not Found' }} + end + end + end end diff --git a/app/controllers/documents_controller.rb b/app/controllers/documents_controller.rb index 994dfbdb..b857caa0 100644 --- a/app/controllers/documents_controller.rb +++ b/app/controllers/documents_controller.rb @@ -71,10 +71,15 @@ def create parse_tag_names(params[:tag_names]) if params[:tag_names] if @document.save #XXX: save! => save - flash[:success] = "文書を追加しました" - redirect_to documents_path + respond_to do |format| + format.html { redirect_to @document, notice: "文書を追加しました" } + format.json { render :show, status: :created, location: @document } + end else - redirect_back fallback_location: new_document_path + respond_to do |format| + format.html { render :new, status: :unprocessable_entity } + format.json { render json: @document.errors, status: :unprocessable_entity } + end end end @@ -85,7 +90,10 @@ def update flash[:success] = "文書を更新しました" redirect_to @document else - redirect_back fallback_location: edit_document_path(@document) + respond_to do |format| + format.html { render :edit, status: :unprocessable_entity } + format.json { render json: @document.errors, status: :unprocessable_entity } + end end end diff --git a/app/controllers/tasks_controller.rb b/app/controllers/tasks_controller.rb index ea0b5cfb..d74ec755 100644 --- a/app/controllers/tasks_controller.rb +++ b/app/controllers/tasks_controller.rb @@ -65,14 +65,19 @@ def create parse_tag_names(params[:tag_names]) if params[:tag_names] if @task.save! - flash[:success] = "タスクを追加しました" matched = task_params[:description].match(/\[AI([0-9]+)\]/) if matched != nil ActionItem.find(matched[1]).update(task_url: tasks_path + "/" + @task.id.to_s) end - redirect_to tasks_path + respond_to do |format| + format.html { redirect_to @task, notice: "タスクを追加しました" } + format.json { render :show, status: :created, location: @task } + end else - redirect_back fallback_location: new_task_path + respond_to do |format| + format.html { render :new, status: :unprocessable_entity } + format.json { render json: @task.errors, status: :unprocessable_entity } + end end end @@ -80,10 +85,15 @@ def create def update parse_tag_names(params[:tag_names]) if params[:tag_names] if @task.update(task_params) - flash[:success] = "タスクを更新しました" - redirect_to tasks_path + respond_to do |format| + format.html { redirect_to @task, notice: "タスクを更新しました." } + format.json { render :show, status: :ok, location: @task } + end else - redirect_back fallback_location: edit_task_path(@task) + respond_to do |format| + format.html { render :edit, status: :unprocessable_entity } + format.json { render json: @task.errors, status: :unprocessable_entity } + end end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 9113cfdb..6200335a 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -31,7 +31,10 @@ def create flash[:success] = "ユーザ登録が完了しました" redirect_to tasks_path else - render 'new' + respond_to do |format| + format.html { redirect_to users_url } + format.json { render status: :bad_request, json: {status: 400, message: "Bad Request"} } + end end end @@ -68,7 +71,11 @@ def user_params end def correct_user - @user = User.find(params[:id]) - redirect_to(users_url) unless current_user?(@user) + if ! current_user?(@user) + respond_to do |format| + format.html { redirect_to users_url } + format.json { render status: 404, json: { status: 404, message: 'Not Found' }} + end + end end end diff --git a/app/views/documents/_document.json.jbuilder b/app/views/documents/_document.json.jbuilder index 34d9eef4..a34f50f3 100644 --- a/app/views/documents/_document.json.jbuilder +++ b/app/views/documents/_document.json.jbuilder @@ -1,2 +1,11 @@ -json.extract! document, :id, :content, :creator_id, :description, :created_at, :updated_at, :project_id, :start_at, :end_at, :location +json.extract! document, :id, :content, :description, :created_at, :updated_at, :start_at, :end_at, :location +json.set! :creator do + json.extract! document.user, :id, :name +end +json.set! :project do + json.extract! document.project, :id, :name +end +json.set! :tags do + json.array! document.tags, :id, :name +end json.url document_url(document, format: :json) diff --git a/app/views/tags/_tag.json.jbuilder b/app/views/tags/_tag.json.jbuilder index d5c7620c..38a028cf 100644 --- a/app/views/tags/_tag.json.jbuilder +++ b/app/views/tags/_tag.json.jbuilder @@ -1,2 +1,8 @@ json.extract! tag, :id, :name, :created_at, :updated_at +json.set! :tasks do + json.array! tag.tasks, :id, :content +end +json.set! :documents do + json.array! tag.documents, :id, :content +end json.url tag_url(tag, format: :json) diff --git a/app/views/tasks/_task.json.jbuilder b/app/views/tasks/_task.json.jbuilder index 19b1892e..ea51d545 100644 --- a/app/views/tasks/_task.json.jbuilder +++ b/app/views/tasks/_task.json.jbuilder @@ -8,4 +8,7 @@ end json.set! :project do json.extract! task.project, :id, :name end +json.set! :tags do + json.array! task.tags, :id, :name +end json.url task_url(task, format: :json) diff --git a/app/views/users/_user.json.jbuilder b/app/views/users/_user.json.jbuilder index df793f1e..26550b76 100644 --- a/app/views/users/_user.json.jbuilder +++ b/app/views/users/_user.json.jbuilder @@ -1,2 +1,2 @@ -json.extract! user, :id, :name, :created_at, :updated_at +json.extract! user, :id, :name, :screen_name, :active, :created_at, :updated_at json.url user_url(user, format: :json) diff --git a/config/initializers/rswag_ui.rb b/config/initializers/rswag_ui.rb new file mode 100644 index 00000000..d84fe7cd --- /dev/null +++ b/config/initializers/rswag_ui.rb @@ -0,0 +1,16 @@ +Rswag::Ui.configure do |c| + + # List the Swagger endpoints that you want to be documented through the + # swagger-ui. The first parameter is the path (absolute or relative to the UI + # host) to the corresponding endpoint and the second is a title that will be + # displayed in the document selector. + # NOTE: If you're using rspec-api to expose Swagger files + # (under openapi_root) as JSON or YAML endpoints, then the list below should + # correspond to the relative paths for those endpoints. + + c.swagger_endpoint '/api-docs/openapi.yaml', 'Rask API' + + # Add Basic Auth in case your API is private + # c.basic_auth_enabled = true + # c.basic_auth_credentials 'username', 'password' +end diff --git a/config/routes.rb b/config/routes.rb index 402f8731..612bc749 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,7 @@ Rails.application.routes.draw do + mount Rswag::Ui::Engine => '/api-docs' + resources :tags resources :api_tokens resources :projects diff --git a/docs/api-specification.md b/docs/api-specification.md new file mode 100644 index 00000000..a7d72ad2 --- /dev/null +++ b/docs/api-specification.md @@ -0,0 +1,368 @@ +# REST API 仕様 + +## 共通項目 +* API のアクセスには API Token が必要です. +* メニューの 「API トークン一覧」から,API トークンを作成,使用してください. +* API アクセス時は,Query,または Body に "api_key" を含めてください. +* API へのアクセスは,使用した API Token を所有するユーザのアクセスとして認識されます. + +* 例 + ```bash + curl 'https://your.rask.url/tasks.json?api_key=' # GET + curl -XPOST -d 'api_key=' 'https://your.rask.url/tasks.json' # POST (or PUT, DELETE) + ``` + +* Response は以下の通りです. + * 200 (Ok): Request は正常に処理されました. + * 400 (Bad Request): Requst Body に不正なデータが含まれています. + * 401 (Unauthorized): API Token が付与されていないか,不正です. + * 403 (Forbidden): 認証されたユーザの権限では,リクエストを処理できません. + * 404 (Not Found): 指定された PATH に対応する API が存在しないか,指定されたリソースが存在しません. + +## Task +### Request Schema +``` +TaskRequest { + (require) "assigner_id": Integer, + (require) "content": String, + "due_at": Datetime, + "description": String, + "project_id": Integer, + "task_state_id": Integer, + "tags": List +} +``` + +### Response Schema +``` +TaskResponse { + "id": Iteger, + "content": String, + "description": String, + "due_at": Daetime, + "created_at": Datetime, + "updated_at": Datetime, + "creator": { + "id": Integer, + "name": String, + }, + "assigner": { + "id": Integer, + "name": String, + }, + "project": { + "id": Integer, + "name": String, + }, + "tags": { + "id": String, + "name": String, + }, + "url": String, +} +``` + +### API +1. Show all tasks + * Method: GET + * PATH: "/tasks.json" + * Request: - + * Response: List +2. Show a task + * Method: GET + * PATH: "/tasks/.json" ("/tasks/1.json") + * Request: - + * Response: TaskResponse +3. Create new task + * Method: POST + * PATH: "/tasks.json" + * Request: TaskRequest + * Response: TaskResponse (newly-created task) +4. Edit a task + * Method: PUT or PATCH + * PATH: "/tasks.json" + * Request: TaskRequest + * Response: TaskResponse (editted task) +5. Delete a task + * Method: DELETE + * PATH: "/tasks/.json" ("/tasks/1.json") + * Request: - + * Response: TaskResponse (deleted task) + +## Document +### Request Schema +``` +DocumentRequest { + (require) "content": String + "description": String + "project_id": Integer + "start_at": Datetime + "end_at": Datetime + "location": String + "tags": List +} + +``` + +### Response Schema +``` +DocumentResponse { + "id": Integer, + "content": String, + "creator": { + "id": Integer, + "name": String, + }, + "description": String, + "created_at": Datetime, + "updated_at": Datetime, + "project": { + "id": Integer, + "name": String, + }, + "start_at": Datetime, + "end_at": Datetime, + "location": Integer, + "tags": { + "id": String, + "name": String, + }, + "url": String, +} +``` + +### API +1. Show all documents + * Method: GET + * PATH: "/documents.json" + * Request: - + * Response: List +2. Show a document + * Method: GET + * PATH: "/documents/.json" ("/documents/1.json") + * Request: - + * Response: DocumentResponse +3. Create new document + * Method: POST + * PATH: "/documents.json" + * Request: DocumentRequest + * Response: DocumentResponse (newly-created document) +4. Edit a document + * Method: PUT or PATCH + * PATH: "/documents/.json" ("/documents/1.json") + * Request: DocumentRequest + * Response: DocumentResponse (editted document) +5. Delete a document + * Method: DELETE + * PATH: "/documents/.json" ("/documents/1.json") + * Request: - + * Response: DocumentResponse (deleted document) + +## User +### Request Schema +``` +UserRequest { + (require) "name": String, + (require) "active": Bool, + (require) "screen_name": String, +} +``` + +### Response Schema +``` +UserResponse { + "id": Integer, + "name": String, + "active": Bool, + "screen_name": String, + "created_at": Datetime, + "updated_at": Datetime, + "url": String, +} +``` + +### API +1. Show all users + * Method: GET + * PATH: "/users.json" + * Request: - + * Response: List +2. Show a user + * Method: GET + * PATH: "/users/.json" ("/users/1.json") + * Request: - + * Response: UserResponse +3. ~~Create new user~~ + * Cannot create user with API +4. Edit a user + * Method: PUT or PATCH + * PATH: "/users/.json" ("/users/1.json") + * Request: UserRequest + * Response: UserResponse (editted user) + * Note: You can edit only your account. +5. Delete a user + * Method: DELETE + * PATH: "/users/.json" ("/users/1.json") + * Request: - + * Response: UserResponse (deleted user) + * Note: You can delete only your account. + +## Project +### Request Schema +``` +ProjectRequest { + (require) "name": String, +} +``` + +### Response Schema +``` +ProjectResponse { + "id": Integer, + "name": String, + "created_at": Datetime, + "updated_at": Datetime, + "user": { + "id": Integer, + "name": String, + }, + "url": String, +} +``` + +### API +1. Show all projects + * Method: GET + * PATH: "/projects.json" + * Request: - + * Response: List +2. Show a project + * Method: GET + * PATH: "/projects/.json" ("/projects/1.json") + * Request: - + * Response: ProjectResponse +3. Create new project + * Method: POST + * PATH: "/projects.json" + * Request: ProjectRequest + * Response: ProjectResponse (newly-created project) +4. Edit a project + * Method: PUT or PATCH + * PATH: "/projects/.json" ("/projects/1.json") + * Request: ProjectRequest + * Response: ProjectResponse (editted project) +5. Delete a project + * Method: DELETE + * PATH: "/projects/.json" ("/projects/1.json") + * Request: - + * Response: ProjectResponse (deleted project) + * Note: If specified project has some tasks, you cannot delete. + +## Tag +### Request Schema +``` +TagRequest { + (require) name: String, +} +``` + +### Response Schema +``` +TagResponse { + "id": Integer, + "name": String, + "docuements": { + "id": Integer + "content": String + }, + "created_at": Datetime, + "updated_at": Datetime, + "url": String, +} +``` + +### API +1. Show all tags + * Method: GET + * PATH: "/tags.json" + * Request: - + * Response: List +2. Show a tag + * Method: GET + * PATH: "/tags/.json" ("/tags/1.json") + * Request: - + * Response: TagResponse +3. Create new tag + * Method: POST + * PATH: "/tags.json" + * Request: TagResponse + * Response: TagResponse (newly-created tag) +4. Edit a tag + * Method: PUT or PATCH + * PATH: "/tags.json" + * Request: TagResponse + * Response: TagResponse (editted tag) +5. Delete a tag + * Method: DELETE + * PATH: "/tags/.json" ("/tags/1.json") + * Request: - + * Response: TagResponse (deleted tag) + * Note: If specified tag has some tasks, you cannot delete. + +## API Token +### Request Schema +``` +APITokenRequest { + (require) description: String, +} +``` + +### Response Schema +``` +APITokenResponse { + "id": Integer, + "secret": String, + "description": String, + "expired_at": Datetime, + "created_at": Datetime, + "updated_at": Datetime, + "user": { + "id": Integer, + "name": String, + }, + "url": String, +} +``` + +### API +1. Show all your API tokens + * Method: GET + * PATH: "/api_tokens.json" + * Request: - + * Response: List + * Note: You can show only your API Tokens +2. Show a API token + * Method: GET + * PATH: "/api_tokens/.json" ("/api_tokens/1.json") + * Request: - + * Response: APITokenResponse + * Note: You can show only your API Token +3. Create new task + * Method: POST + * PATH: "/api_tokens.json" + * Request: APITokenRequest + * Response: APITokenResponse (newly-created API Token) + * Note: New task is owned by your account. +4. Edit a API Token + * Method: PUT or PATCH + * PATH: "/api_tokens/.json" ("/api_tokens/1.json") + * Request: APITokenRequest + * Response: APITokenResponse (editted API Token) + * Note: You can edit only your API Token +5. Delete a API token + * Method: DELETE + * PATH: "/api_tokens/.json" ("/api_tokens/1.json") + * Request: - + * Response: APITokenResponse (deleted API Token) + * Note: You can delete only your API Token + diff --git a/public/api-docs/openapi.yaml b/public/api-docs/openapi.yaml new file mode 100644 index 00000000..6cedd824 --- /dev/null +++ b/public/api-docs/openapi.yaml @@ -0,0 +1,1084 @@ +openapi: 3.0.3 + +info: + title: RASK API + description: OpenAPI specification for RASK API + version: 2.0.0 + +servers: +- url: https://rask.nomlab.org + description: "本番環境" +- url: http://localhost:3000 + description: "開発サーバ" + +security: + - ApiKey: [] + +tags: + - name: project + description: Project + - name: task + description: Task + - name: document + description: Document + - name: tag + description: Tag + - name: user + description: User + - name: api_token + description: API Token + +components: + schemas: + # Common Schema + idNameSet: + type: object + properties: + id: + type: integer + example: 1 + name: + type: string + example: Name + + # Project Schema + projectRequest: + required: + - name + type: object + properties: + name: + type: string + example: Example Project + projectResponse: + type: object + properties: + id: + type: integer + format: int64 + example: 1 + name: + type: string + example: Example Project + created_at: + type: string + example: 2025-01-01 1:02:03+9:00 + updated_at: + type: string + example: 2025-01-01 1:02:03+9:00 + user: + $ref: '#/components/schemas/idNameSet' + url: + type: string + example: https://example.com/path-to-resource/1 + + # Task Schema + taskRequest: + required: + - assigner_id + - content + type: object + properties: + assigner_id: + type: integer + format: int64 + example: 1 + content: + type: string + example: Example Task + due_at: + type: string + example: 2025/01/01 23:59 + description: + type: string + example: This task is example + project_id: + type: string + example: 1 + task_state_id: + type: integer + format: int64 + example: 1 + tags: + type: array + items: + type: string + taskResponse: + type: object + properties: + id: + type: integer + format: int64 + example: 1 + content: + type: string + example: Example Task + description: + type: string + example: This task is example + due_at: + type: string + example: 2025/01/01 23:59 + creator: + $ref: '#/components/schemas/idNameSet' + assigner: + $ref: '#/components/schemas/idNameSet' + project: + $ref: '#/components/schemas/idNameSet' + tags: + type: array + items: + type: string + example: tag1 + created_at: + type: string + example: 2025-01-01 1:02:03+9:00 + updated_at: + type: string + example: 2025-01-01 1:02:03+9:00 + url: + type: string + example: https://example.com/path-to-resource/1 + + # Tag Schema + tagRequest: + required: + - name + type: object + properties: + name: + type: string + example: Example Tag + tagResponse: + type: object + properties: + id: + type: integer + format: int64 + example: 1 + name: + type: string + example: Example Tag + tasks: + type: array + items: + $ref: '#/components/schemas/idNameSet' + documents: + type: array + items: + $ref: '#/components/schemas/idNameSet' + created_at: + type: string + example: 2025-01-01 1:02:03+9:00 + updated_at: + type: string + example: 2025-01-01 1:02:03+9:00 + url: + type: string + example: https://example.com/path-to-resource/1 + + # Document Schema + documentRequest: + required: + - content + type: object + properties: + content: + type: string + example: Example Document + description: + type: string + example: This document is example + project_id: + type: string + example: 1 + start_at: + type: string + example: 2025/01/01 15:00 + end_at: + type: string + example: 2025/01/01 17:00 + location: + type: string + example: Meeting Room 1 + tags: + type: array + items: + type: string + documentResponse: + type: object + properties: + id: + type: integer + format: int64 + example: 1 + content: + type: string + example: Example Task + description: + type: string + example: This task is example + creator: + $ref: '#/components/schemas/idNameSet' + project: + $ref: '#/components/schemas/idNameSet' + start_at: + type: string + example: 2025/01/01 15:00 + end_at: + type: string + example: 2025/01/01 17:00 + location: + type: string + example: Meeting Room 1 + tags: + type: array + items: + type: string + example: tag1 + created_at: + type: string + example: 2025-01-01 1:02:03+9:00 + updated_at: + type: string + example: 2025-01-01 1:02:03+9:00 + url: + type: string + example: https://example.com/path-to-resource/1 + + # User Schema + userRequest: + required: + - name + - screen_name + - active + type: object + properties: + name: + type: string + example: Tarou Yamada + screen_name: + type: string + example: yamada + active: + type: boolean + example: true + userResponse: + type: object + properties: + id: + type: integer + format: int64 + example: 1 + name: + type: string + example: Tarou Yamada + screen_name: + type: string + example: yamada + active: + type: boolean + example: true + created_at: + type: string + example: 2025-01-01 1:02:03+9:00 + updated_at: + type: string + example: 2025-01-01 1:02:03+9:00 + url: + type: string + example: https://example.com/path-to-resource/1 + + # API Token Schema + apiTokenRequest: + required: + - description + type: object + properties: + description: + type: string + example: Example API Token + apiTokenResponse: + type: object + properties: + id: + type: integer + format: int64 + example: 1 + secret: + type: string + example: rask-1234567890ThisIsExampleAPIToken + description: + type: string + example: Example API Token + user: + $ref: '#/components/schemas/idNameSet' + created_at: + type: string + example: 2025-01-01 1:02:03+9:00 + updated_at: + type: string + example: 2025-01-01 1:02:03+9:00 + url: + type: string + example: https://example.com/path-to-resource/1 + + # Error Schema + Error: + type: object + properties: + code: + type: string + message: + type: string + required: + - code + - message + + requestBodies: + # Project Requests + project: + description: Data for the project to be added or updated + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/projectRequest' + + # Task Requests + task: + description: Data for the task to be added or updated + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/taskRequest' + + # Document Requests + document: + description: Data for the document to be added or updated + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/documentRequest' + + # Tag Requests + tag: + description: Data for the tag to be added or updated + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/tagRequest' + + # User Requests + user: + description: Data for the user to be updated + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/userRequest' + + # APIToken Requests + apiToken: + description: Data for the API Token to be added or updated + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/apiTokenRequest' + + responses: + # Error Responses + BadRequest: + description: Invalid Request Body + Unauthorized: + description: API key is missing or invalid + Forbidden: + description: Request from the user associated with API key is forbidden + NotFound: + description: API or specified resource is not found + PreconditionFailed: + description: Cannot delete the resource that is associated with any other resources + UnexpectedError: + description: Unexpected Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + + # Project Responses + project: + description: Project data + content: + application/json: + schema: + $ref: '#/components/schemas/projectResponse' + projectArray: + description: List of projects + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/projectResponse' + + # Task Responses + task: + description: Task data + content: + application/json: + schema: + $ref: '#/components/schemas/taskResponse' + taskArray: + description: List of Tasks + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/taskResponse' + + # Document Responses + document: + description: Document data + content: + application/json: + schema: + $ref: '#/components/schemas/documentResponse' + documentArray: + description: List of documents + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/documentResponse' + + # Tag Responses + tag: + description: Tag data + content: + application/json: + schema: + $ref: '#/components/schemas/tagResponse' + tagArray: + description: List of tags + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/tagResponse' + + # User Responses + user: + description: User data + content: + application/json: + schema: + $ref: '#/components/schemas/userResponse' + userArray: + description: List of users + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/userResponse' + + # API Token Responses + apiToken: + description: API Token data + content: + application/json: + schema: + $ref: '#/components/schemas/apiTokenResponse' + apiTokenArray: + description: List of API Tokens + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/apiTokenResponse' + + securitySchemes: + ApiKey: + type: apiKey + in: query + name: api_key + +paths: + ################### + ## Project API ## + ################### + /projects: + get: + tags: + - project + summary: Get all of projects + description: This API returns all of projects + operationId: projectIndex + responses: + '200': + $ref: '#/components/responses/projectArray' + '401': + $ref: '#/components/responses/Unauthorized' + default: + $ref: "#/components/responses/UnexpectedError" + post: + tags: + - project + summary: Add new single project + description: This API can add a new project and returns the newly-created project + operationId: projectCreate + requestBody: + $ref: '#/components/requestBodies/project' + responses: + '200': + $ref: '#/components/responses/projectArray' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + default: + $ref: "#/components/responses/UnexpectedError" + /projects/{projectId}: + parameters: + - name: projectId + in: path + description: ID of project + required: true + schema: + type: integer + format: int64 + get: + tags: + - project + summary: Get the specified project + description: This API returns the specified project + operationId: projectShow + responses: + '200': + $ref: '#/components/responses/project' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: "#/components/responses/UnexpectedError" + put: + tags: + - project + summary: Update the specified project + description: This API can update the specified project and returns the updated project + operationId: projectUpdate + requestBody: + $ref: '#/components/requestBodies/project' + responses: + '200': + $ref: '#/components/responses/project' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: "#/components/responses/UnexpectedError" + delete: + tags: + - project + summary: Delete the specified project + description: This API can delete the specified project and returns the deleted project + operationId: projectDelete + responses: + '200': + $ref: '#/components/responses/project' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + '413': + $ref: '#/components/responses/PreconditionFailed' + default: + $ref: "#/components/responses/UnexpectedError" + + ################## + ## Task API ## + ################## + /tasks: + get: + tags: + - task + summary: Get all of tasks + description: This API returns all of tasks + operationId: taskIndex + responses: + '200': + $ref: '#/components/responses/taskArray' + '401': + $ref: '#/components/responses/Unauthorized' + default: + $ref: "#/components/responses/UnexpectedError" + post: + tags: + - task + summary: Add new single task + description: This API can add a new task and returns the newly-created task + operationId: taskCreate + requestBody: + $ref: '#/components/requestBodies/task' + responses: + '200': + $ref: '#/components/responses/taskArray' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + default: + $ref: "#/components/responses/UnexpectedError" + /tasks/{taskId}: + parameters: + - name: taskId + in: path + description: ID of task + required: true + schema: + type: integer + format: int64 + get: + tags: + - task + summary: Get the specified task + description: This API returns the specified task + operationId: taskShow + responses: + '200': + $ref: '#/components/responses/task' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: "#/components/responses/UnexpectedError" + put: + tags: + - task + summary: Update the specified task + description: This API can update the specified task and returns the updated task + operationId: taskUpdate + requestBody: + $ref: '#/components/requestBodies/task' + responses: + '200': + $ref: '#/components/responses/task' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: "#/components/responses/UnexpectedError" + delete: + tags: + - task + summary: Delete the specified task + description: |- + This API can delete the specified task and returns the deleted task + This API can delete only the project that is not associated with any tasks and any documents, otherwise returns 413 (PreconditionFailed) + operationId: taskDelete + responses: + '200': + $ref: '#/components/responses/task' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: "#/components/responses/UnexpectedError" + + #################### + ## Document API ## + #################### + /documents: + get: + tags: + - document + summary: Get all of documents + description: This API returns all of documents + operationId: documentIndex + responses: + '200': + $ref: '#/components/responses/documentArray' + '401': + $ref: '#/components/responses/Unauthorized' + default: + $ref: "#/components/responses/UnexpectedError" + post: + tags: + - document + summary: Add new single document + description: This API can add a new document and returns the newly-created document + operationId: documentCreate + requestBody: + $ref: '#/components/requestBodies/document' + responses: + '200': + $ref: '#/components/responses/documentArray' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + default: + $ref: "#/components/responses/UnexpectedError" + /documents/{documentId}: + parameters: + - name: documentId + in: path + description: ID of document + required: true + schema: + type: integer + format: int64 + get: + tags: + - document + summary: Get the specified document + description: This API can returns the specified document + operationId: documentShow + responses: + '200': + $ref: '#/components/responses/document' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: "#/components/responses/UnexpectedError" + put: + tags: + - document + summary: Update the specified document + description: This API can update the specified document and returns updated document + operationId: documentUpdate + requestBody: + $ref: '#/components/requestBodies/document' + responses: + '200': + $ref: '#/components/responses/document' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: "#/components/responses/UnexpectedError" + delete: + tags: + - document + summary: Delete the specified document + description: This API can delete the specified document and returns deleted document + operationId: documentDelete + responses: + '200': + $ref: '#/components/responses/document' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: "#/components/responses/UnexpectedError" + + #################### + ## Tag API ## + #################### + /tags: + get: + tags: + - tag + summary: Get all of tags + description: This API returns all of tags + operationId: tagIndex + responses: + '200': + $ref: '#/components/responses/tagArray' + '401': + $ref: '#/components/responses/Unauthorized' + default: + $ref: "#/components/responses/UnexpectedError" + post: + tags: + - tag + summary: Add new single tag + description: This API can add a new tag and returns the newly-created tag + operationId: tagCreate + requestBody: + $ref: '#/components/requestBodies/tag' + responses: + '200': + $ref: '#/components/responses/tagArray' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + default: + $ref: "#/components/responses/UnexpectedError" + /tags/{tagId}: + parameters: + - name: tagId + in: path + description: ID of tag + required: true + schema: + type: integer + format: int64 + get: + tags: + - tag + summary: Get the specified tag + description: This API returns the specified tag + operationId: tagShow + responses: + '200': + $ref: '#/components/responses/tag' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: "#/components/responses/UnexpectedError" + put: + tags: + - tag + summary: Update the specified tag + description: This API can update the specified tag and returns the updated tag + operationId: tagUpdate + requestBody: + $ref: '#/components/requestBodies/tag' + responses: + '200': + $ref: '#/components/responses/tag' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: "#/components/responses/UnexpectedError" + delete: + tags: + - tag + summary: Delete the specified tag + description: |- + This API can delete the specified tag and returns the deleted tag + This API can delete only the tag that is not associated with any tasks and any documents, otherwise returns 413 (PreconditionFailed) + operationId: tagDelete + responses: + '200': + $ref: '#/components/responses/tag' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + '413': + $ref: '#/components/responses/PreconditionFailed' + default: + $ref: "#/components/responses/UnexpectedError" + + #################### + ## User API ## + #################### + /users: + get: + tags: + - user + summary: Get all of users + description: This API returns all of users + operationId: userIndex + responses: + '200': + $ref: '#/components/responses/userArray' + '401': + $ref: '#/components/responses/Unauthorized' + default: + $ref: "#/components/responses/UnexpectedError" + /users/{userId}: + parameters: + - name: userId + in: path + description: ID of user + required: true + schema: + type: integer + format: int64 + get: + tags: + - user + summary: Get the specified user + description: This API returns the specified user + operationId: userShow + responses: + '200': + $ref: '#/components/responses/user' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: "#/components/responses/UnexpectedError" + put: + tags: + - user + summary: Update the specified user + description: |- + This API can update the specified user and returns updated user + This API can update only your user account, otherwise returns 403 (Forbidden) + operationId: userUpdate + requestBody: + $ref: '#/components/requestBodies/user' + responses: + '200': + $ref: '#/components/responses/user' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: "#/components/responses/UnexpectedError" + delete: + tags: + - user + summary: Delete the specified user + description: |- + This API can delete the specified user and returns deleted user + This API can delete only your accont, otherwise returns 403 (Forbidden) + operationId: userDelete + responses: + '200': + $ref: '#/components/responses/user' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: "#/components/responses/UnexpectedError" + + ##################### + ## API Token API ## + ##################### + /api_tokens: + get: + tags: + - api_token + summary: Get all of your API Tokens + description: This API returns your API Tokens + operationId: apiTokenIndex + responses: + '200': + $ref: '#/components/responses/apiTokenArray' + '401': + $ref: '#/components/responses/Unauthorized' + default: + $ref: "#/components/responses/UnexpectedError" + post: + tags: + - api_token + summary: Add new single API Token + description: |- + This API can add a new API Token and returns the newly-created API Token + Newly-created API Token is automatically owned by your account + operationId: apiTokenCreate + requestBody: + $ref: '#/components/requestBodies/apiToken' + responses: + '200': + $ref: '#/components/responses/apiTokenArray' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + default: + $ref: "#/components/responses/UnexpectedError" + /api_tokens/{apiTokenId}: + parameters: + - name: apiTokenId + in: path + description: ID of API Token + required: true + schema: + type: integer + format: int64 + get: + tags: + - api_token + summary: Get the specified API Token + description: |- + This API returns the specified API Token + This API can get only your API Key, otherwise returns 403 (Forbidden) + operationId: apiTokenShow + responses: + '200': + $ref: '#/components/responses/apiToken' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: "#/components/responses/UnexpectedError" + put: + tags: + - api_token + summary: Update the specified API Token + description: |- + This API can update the specified API Token, and returns updated API Token + This API can update your API Key (including the API Key using this request), otherwise returns 403 (Forbidden) + operationId: apiTokenUpdate + requestBody: + $ref: '#/components/requestBodies/apiToken' + responses: + '200': + $ref: '#/components/responses/apiToken' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: "#/components/responses/UnexpectedError" + delete: + tags: + - api_token + summary: Delete the specified API Token + description: |- + This API can delete the specified API Token, and returns deleted API Token + This API can delete only your API Key (including the API Key using this request), otherwise returns 403 (Forbidden) + operationId: apiTokenDelete + responses: + '200': + $ref: '#/components/responses/apiToken' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + default: + $ref: "#/components/responses/UnexpectedError" diff --git a/test/controllers/tasks_controller_test.rb b/test/controllers/tasks_controller_test.rb index 0e828958..0893f1a0 100644 --- a/test/controllers/tasks_controller_test.rb +++ b/test/controllers/tasks_controller_test.rb @@ -36,7 +36,7 @@ class TasksControllerTest < ActionDispatch::IntegrationTest post tasks_url, params: { task: { content: @task.content, creator_id: @task.creator_id, assigner_id: @task.assigner_id , due_at: @task.due_at, description: @task.description, project_id: @task.project_id, task_state_id: @task.task_state_id} } end - assert_redirected_to tasks_url + assert_redirected_to task_url(Task.last) end test "should redirect create to login" do @@ -58,7 +58,7 @@ class TasksControllerTest < ActionDispatch::IntegrationTest test "should update task" do log_in_as(@user) patch task_url(@task), params: { task: { content: @task.content, creator_id: @task.creator_id, task_state_id: @task.task_state_id } } - assert_redirected_to tasks_url + assert_redirected_to task_url(@task) end test "should redirect update to login" do