├── .devcontainer ├── Dockerfile ├── devcontainer.json └── docker-compose.yml ├── .dockerignore ├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ └── known_hosts ├── .gitignore ├── .gitmodules ├── Dockerfile ├── Dockerfile.production ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.rdoc ├── Rakefile ├── Steepfile ├── app ├── assets │ ├── config │ │ └── manifest.js │ ├── images │ │ └── .keep │ ├── javascripts │ │ └── application.js │ └── stylesheets │ │ ├── _articles.scss │ │ ├── _base.scss │ │ ├── admin │ │ └── articles.scss │ │ └── application.scss ├── avo │ └── resources │ │ └── article_resource.rb ├── controllers │ ├── application_controller.rb │ ├── articles_controller.rb │ ├── avo │ │ └── articles_controller.rb │ ├── concerns │ │ └── .keep │ ├── graphql_controller.rb │ └── sessions_controller.rb ├── graphql │ ├── mutations │ │ └── .keep │ ├── tdnm_schema.rb │ └── types │ │ ├── .keep │ │ ├── article_type.rb │ │ ├── base_enum.rb │ │ ├── base_input_object.rb │ │ ├── base_interface.rb │ │ ├── base_object.rb │ │ ├── base_scalar.rb │ │ ├── base_union.rb │ │ ├── mutation_type.rb │ │ └── query_type.rb ├── helpers │ ├── application_helper.rb │ └── articles_helper.rb ├── jobs │ └── application_job.rb ├── mailers │ └── .keep ├── models │ ├── .keep │ ├── application_record.rb │ ├── article.rb │ ├── concerns │ │ └── .keep │ └── weblog.rb └── views │ ├── articles │ ├── index.atom.builder │ ├── index.html.slim │ └── show.html.slim │ ├── kaminari │ ├── _first_page.html.slim │ ├── _gap.html.slim │ ├── _last_page.html.slim │ ├── _next_page.html.slim │ ├── _page.html.slim │ ├── _paginator.html.slim │ └── _prev_page.html.slim │ ├── layouts │ └── application.html.slim │ └── sessions │ └── new.html.slim ├── bin ├── bundle ├── rails ├── rake ├── render-build.sh ├── setup ├── start ├── steep └── yarn ├── config.ru ├── config ├── application.rb ├── boot.rb ├── cable.yml ├── credentials.yml.enc ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── application_controller_renderer.rb │ ├── assets.rb │ ├── avo.rb │ ├── backtrace_silencers.rb │ ├── content_security_policy.rb │ ├── cookies_serializer.rb │ ├── filter_parameter_logging.rb │ ├── inflections.rb │ ├── meta_tags.rb │ ├── mime_types.rb │ ├── omniauth.rb │ ├── permissions_policy.rb │ ├── session_store.rb │ └── wrap_parameters.rb ├── locales │ ├── avo.en.yml │ └── en.yml ├── puma.rb ├── routes.rb ├── sitemap.rb ├── spring.rb └── storage.yml ├── db ├── migrate │ ├── 20150803141807_create_articles.rb │ ├── 20150804044739_create_weblogs.rb │ ├── 20160110151755_change_column_article_body_to_text.rb │ ├── 20161023132949_add_draft_to_articles.rb │ ├── 20180326163716_add_default_eye_catching_image_url_to_weblog.rb │ ├── 20180416143233_rename_url_title_to_slug_on_articles.rb │ ├── 20180416150121_add_eye_catching_image_url_to_articles.rb │ ├── 20190604125626_change_articles_eyecatching_url_size.rb │ ├── 20190924161405_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb │ ├── 20200324153331_add_index_to_articles_published_on.rb │ ├── 20210908153117_add_unique_index_to_article_title.rb │ └── 20230303004038_rename_column_eye_catching_image_url_to_featured_imaeg_url.rb ├── schema.rb └── seeds.rb ├── docker-compose.yml ├── lib ├── assets │ └── .keep └── tasks │ ├── .keep │ ├── import.thor │ └── rbs.rake ├── log └── .keep ├── public ├── 404.html ├── 422.html ├── 500.html ├── favicon.ico └── robots.txt ├── sig └── rbs_rails │ ├── app │ └── models │ │ ├── article.rbs │ │ └── weblog.rbs │ ├── model_dependencies.rbs │ └── path_helpers.rbs ├── test ├── application_system_test_case.rb ├── controllers │ ├── .keep │ └── articles_controller_test.rb ├── fixtures │ ├── .keep │ ├── articles.yml │ └── weblogs.yml ├── helpers │ └── .keep ├── integration │ └── .keep ├── mailers │ └── .keep ├── models │ ├── .keep │ ├── article_test.rb │ └── weblog_test.rb ├── system │ └── articles_test.rb └── test_helper.rb └── tmp └── .keep /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rubylang/ruby:2.7.0-bionic 2 | 3 | RUN apt-get update -q && apt-get install -y --no-install-recommends -q \ 4 | curl \ 5 | g++ \ 6 | gnupg \ 7 | libmysqlclient-dev \ 8 | mysql-client \ 9 | openssh-client \ 10 | && apt-get clean && rm -rf /var/lib/apt/lists/* 11 | 12 | RUN curl -sL https://deb.nodesource.com/setup_12.x | bash - \ 13 | && apt-get update -q && apt-get install -y --no-install-recommends -q nodejs \ 14 | && apt-get clean && rm -rf /var/lib/apt/lists/* 15 | 16 | RUN bundle config jobs 3 17 | RUN bundle config path ./vendor/bundle 18 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.101.1/containers/docker-existing-docker-compose 3 | // If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml. 4 | { 5 | "name": "Existing Docker Compose (Extend)", 6 | 7 | // Update the 'dockerComposeFile' list if you have more compose files or use different names. 8 | // The .devcontainer/docker-compose.yml file contains any overrides you need/want to make. 9 | "dockerComposeFile": [ 10 | "../docker-compose.yml", 11 | "docker-compose.yml" 12 | ], 13 | 14 | // The 'service' property is the name of the service for the container that VS Code should 15 | // use. Update this value and .devcontainer/docker-compose.yml to the real service name. 16 | "service": "app", 17 | 18 | // The optional 'workspaceFolder' property is the path VS Code should open by default when 19 | // connected. This is typically a file mount in .devcontainer/docker-compose.yml 20 | "workspaceFolder": "/workspace", 21 | 22 | // Set *default* container specific settings.json values on container create. 23 | "settings": { 24 | "terminal.integrated.shell.linux": null 25 | }, 26 | 27 | // Add the IDs of extensions you want installed when the container is created. 28 | "extensions": [] 29 | 30 | // Uncomment the next line if you want start specific services in your Docker Compose config. 31 | // "runServices": [], 32 | 33 | // Uncomment the next line if you want to keep your containers running after VS Code shuts down. 34 | // "shutdownAction": "none", 35 | 36 | // Uncomment the next line to run commands after the container is created - for example installing git. 37 | // "postCreateCommand": "apt-get update && apt-get install -y git", 38 | 39 | // Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root. 40 | // "remoteUser": "vscode" 41 | } 42 | -------------------------------------------------------------------------------- /.devcontainer/docker-compose.yml: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------------------------------------- 2 | # Copyright (c) Microsoft Corporation. All rights reserved. 3 | # Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. 4 | #------------------------------------------------------------------------------------------------------------- 5 | 6 | version: '3' 7 | services: 8 | # Update this to the name of the service you want to work with in your docker-compose.yml file 9 | app: 10 | # You may want to add a non-root user to your Dockerfile and uncomment the line below 11 | # to cause all processes to run as this user. Once present, you can also simply 12 | # use the "remoteUser" property in devcontainer.json if you just want VS Code and 13 | # its sub-processes (terminals, tasks, debugging) to execute as the user. On Linux, 14 | # you may need to ensure the UID and GID of the container user you create matches your 15 | # local user. See https://aka.ms/vscode-remote/containers/non-root for details. 16 | # user: vscode 17 | 18 | # Uncomment if you want to add a different Dockerfile in the .devcontainer folder 19 | build: 20 | context: .devcontainer 21 | dockerfile: Dockerfile 22 | 23 | # Uncomment if you want to expose any additional ports. The snippet below exposes port 3000. 24 | # ports: 25 | # - 3000:3000 26 | 27 | volumes: 28 | # Update this to wherever you want VS Code to mount the folder of your project 29 | - .:/workspace:cached 30 | - bundle_cache:/workspace/vendor/bundle 31 | 32 | # Uncomment the next line to use Docker from inside the container. See https://aka.ms/vscode-remote/samples/docker-in-docker-compose for details. 33 | # - /var/run/docker.sock:/var/run/docker.sock 34 | 35 | # Uncomment the next four lines if you will use a ptrace-based debugger like C++, Go, and Rust. 36 | # cap_add: 37 | # - SYS_PTRACE 38 | # security_opt: 39 | # - seccomp:unconfined 40 | 41 | # Overrides default command so things don't shut down after the process ends. 42 | command: /bin/sh -c "while sleep 1000; do :; done" 43 | 44 | volumes: 45 | bundle_cache: 46 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .dockerignore 2 | 3 | .bundle 4 | .ruby-version 5 | 6 | .git 7 | .gitignore 8 | 9 | .circleci 10 | 11 | config/master.key 12 | 13 | log 14 | node_modules 15 | tmp 16 | vendor 17 | 18 | tdnm.env 19 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: bundler 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "20:00" 8 | open-pull-requests-limit: 10 9 | assignees: 10 | - kenchan 11 | versioning-strategy: lockfile-only 12 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | env: 6 | RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }} 7 | 8 | jobs: 9 | test: 10 | runs-on: ubuntu-latest 11 | services: 12 | postgres: 13 | image: postgres:14 14 | env: 15 | POSTGRES_PASSWORD: postgres 16 | options: --health-cmd=pg_isready --health-interval=10s --health-timeout=5s --health-retries=3 17 | ports: 18 | - 5432:5432 19 | 20 | steps: 21 | - uses: actions/checkout@v2 22 | 23 | - name: Setup Ruby 24 | uses: ruby/setup-ruby@v1 25 | with: 26 | ruby-version: 3.1 27 | bundler-cache: true 28 | 29 | - name: Setup database 30 | run: bin/rails db:prepare 31 | env: 32 | DATABASE_PORT: 5432 33 | DATABASE_PASSWORD: postgres 34 | 35 | - name: Run tests 36 | run: bin/rails test 37 | env: 38 | DATABASE_PORT: 5432 39 | DATABASE_PASSWORD: postgres 40 | 41 | - name: Run system tests 42 | run: bin/rails test:system 43 | env: 44 | DATABASE_PORT: 5432 45 | DATABASE_PASSWORD: postgres 46 | -------------------------------------------------------------------------------- /.github/workflows/known_hosts: -------------------------------------------------------------------------------- 1 | |1|dNqLqa9OAvZdkit8qPBEySDXKxQ=|pWoNJhTUgrRvkNfxaIMMJNcDi7U= ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCrbTJsCPOdmAel+2/gW0ziUsOveWyOjfWm7f4UX1TcVpPI1zqDPcReTZybYwLvdIaIzK9GgmUZ3Y8n2Pi9YD90Am13xNMHULsg/mt90r9THfC35m8rxnzUJ/DXX0T3QQD9ve69DOCsRe3YRgdQOHUeK4LwVSFYTwVN0fmkIl4a3MweFiu9r42OGtPE9r2Kq4kmBcgLFzbO006eCs2Q2V2kj9AEt3zvIPkV8NJKAJxUEBIEadxIkgULCxDAdwa7UXJjNFGb7xFg+n+lXRMHfH3OhakbHjroTCkuxnBKwcJqGSIvlUZ9Ztw4qGHkUcfZc6HDqFRfNZLb3jnkFImZHKzZ 2 | |1|dseivxwEnXaRQWLWbLT/EC7Iiqw=|AczEhQS6lhdxKAaYQNahUiTKDbU= ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBsyEaY2RqedDxTP3bvdpdIG9hm9Kgr97apkI7RTrm2r 3 | |1|Y09qAY+b1wpHMue6gY9SIvyBvL4=|MozEgll+LusLMI6xAnQCCiRIwYE= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBC4pfoNkPrtuW1qHg0wFetlh1/Dhpz2cwgCfMlUBpFSpn8ZUTo97/thZdmu5HFBGpYEZ3pOh8M6VTo+PD2MkAWw= 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore the default SQLite database. 11 | /db/*.sqlite3 12 | /db/*.sqlite3-journal 13 | 14 | # Ignore all logfiles and tempfiles. 15 | /log/* 16 | /tmp/* 17 | !/log/.keep 18 | !/tmp/.keep 19 | 20 | /node_modules 21 | /yarn-error.log 22 | 23 | .byebug_history 24 | 25 | # Ignore master key for decrypting credentials and more. 26 | /config/master.key 27 | 28 | tdnm.env 29 | 30 | /vendor/* 31 | !/vendor/rbs 32 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/rbs/gem_rbs_collection"] 2 | path = vendor/rbs/gem_rbs_collection 3 | url = https://github.com/ruby/gem_rbs_collection.git 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rubylang/ruby:3.1-dev-jammy 2 | 3 | RUN apt-get update -q && apt-get install -y --no-install-recommends -q \ 4 | g++ \ 5 | postgresql-client \ 6 | libpq-dev \ 7 | wait-for-it \ 8 | automake \ 9 | libtool \ 10 | libyaml-dev \ 11 | && apt-get clean && rm -rf /var/lib/apt/lists/* 12 | 13 | RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - \ 14 | && apt-get update -q && apt-get install -y --no-install-recommends -q nodejs \ 15 | && apt-get clean && rm -rf /var/lib/apt/lists/* 16 | 17 | EXPOSE 3000 18 | WORKDIR /app 19 | 20 | RUN bundle config set path /app/vendor/bundle 21 | -------------------------------------------------------------------------------- /Dockerfile.production: -------------------------------------------------------------------------------- 1 | FROM rubylang/ruby:3.1 2 | 3 | ENV RAILS_ENV production 4 | ENV RAILS_SERVE_STATIC_FILES true 5 | ENV RAILS_LOG_TO_STDOUT true 6 | 7 | WORKDIR /app 8 | 9 | RUN apt-get update -q && apt-get install -y --no-install-recommends -q \ 10 | g++ \ 11 | postgresql-client \ 12 | libpq-dev \ 13 | automake \ 14 | libtool \ 15 | && apt-get clean && rm -rf /var/lib/apt/lists/* 16 | 17 | RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - \ 18 | && apt-get update -q && apt-get install -y --no-install-recommends -q nodejs \ 19 | && apt-get clean && rm -rf /var/lib/apt/lists/* 20 | 21 | RUN bundle config set deploytment true 22 | 23 | COPY Gemfile* /app 24 | RUN bundle install 25 | 26 | COPY . /app 27 | 28 | CMD ["bin/start"] 29 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | git_source(:github) do |repo_name| 4 | repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") 5 | "https://github.com/#{repo_name}.git" 6 | end 7 | 8 | gem 'rails', '~> 7.0.0' 9 | 10 | gem 'commonmarker' 11 | gem 'graphql' 12 | gem 'jbuilder' 13 | gem 'kaminari' 14 | gem 'marked-rails' 15 | gem 'meta-tags' 16 | gem 'pg' 17 | gem 'puma' 18 | gem 'sass-rails' 19 | gem 'sdoc', '~> 1.0.0', group: :doc 20 | gem 'sitemap_generator' 21 | gem 'slim-rails' 22 | gem 'uglifier' 23 | gem 'turbo-rails', '~> 1.0.0' 24 | gem 'avo' 25 | gem 'omniauth-siwe', github: 'spruceid/omniauth-siwe', branch: 'main' 26 | gem "omniauth-rails_csrf_protection" 27 | 28 | group :production do 29 | gem 'lograge' 30 | gem 'rails_12factor' 31 | gem 'stackdriver' 32 | end 33 | 34 | group :development do 35 | gem 'graphiql-rails' 36 | gem 'rbs_rails', require: false 37 | end 38 | 39 | group :development, :test do 40 | gem 'byebug' 41 | gem 'capybara' 42 | gem 'listen' 43 | gem 'pry-rails' 44 | gem 'selenium-webdriver' 45 | end 46 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GIT 2 | remote: https://github.com/spruceid/omniauth-siwe.git 3 | revision: 1c08b02d25c5eac86e1a8b00bcc6af05fc7e1858 4 | branch: main 5 | specs: 6 | omniauth-siwe (0.1.0) 7 | bcrypt 8 | omniauth 9 | omniauth_openid_connect 10 | siwe 11 | 12 | GEM 13 | remote: https://rubygems.org/ 14 | specs: 15 | actioncable (7.0.8) 16 | actionpack (= 7.0.8) 17 | activesupport (= 7.0.8) 18 | nio4r (~> 2.0) 19 | websocket-driver (>= 0.6.1) 20 | actionmailbox (7.0.8) 21 | actionpack (= 7.0.8) 22 | activejob (= 7.0.8) 23 | activerecord (= 7.0.8) 24 | activestorage (= 7.0.8) 25 | activesupport (= 7.0.8) 26 | mail (>= 2.7.1) 27 | net-imap 28 | net-pop 29 | net-smtp 30 | actionmailer (7.0.8) 31 | actionpack (= 7.0.8) 32 | actionview (= 7.0.8) 33 | activejob (= 7.0.8) 34 | activesupport (= 7.0.8) 35 | mail (~> 2.5, >= 2.5.4) 36 | net-imap 37 | net-pop 38 | net-smtp 39 | rails-dom-testing (~> 2.0) 40 | actionpack (7.0.8) 41 | actionview (= 7.0.8) 42 | activesupport (= 7.0.8) 43 | rack (~> 2.0, >= 2.2.4) 44 | rack-test (>= 0.6.3) 45 | rails-dom-testing (~> 2.0) 46 | rails-html-sanitizer (~> 1.0, >= 1.2.0) 47 | actiontext (7.0.8) 48 | actionpack (= 7.0.8) 49 | activerecord (= 7.0.8) 50 | activestorage (= 7.0.8) 51 | activesupport (= 7.0.8) 52 | globalid (>= 0.6.0) 53 | nokogiri (>= 1.8.5) 54 | actionview (7.0.8) 55 | activesupport (= 7.0.8) 56 | builder (~> 3.1) 57 | erubi (~> 1.4) 58 | rails-dom-testing (~> 2.0) 59 | rails-html-sanitizer (~> 1.1, >= 1.2.0) 60 | active_link_to (1.0.5) 61 | actionpack 62 | addressable 63 | activejob (7.0.8) 64 | activesupport (= 7.0.8) 65 | globalid (>= 0.3.6) 66 | activemodel (7.0.8) 67 | activesupport (= 7.0.8) 68 | activerecord (7.0.8) 69 | activemodel (= 7.0.8) 70 | activesupport (= 7.0.8) 71 | activestorage (7.0.8) 72 | actionpack (= 7.0.8) 73 | activejob (= 7.0.8) 74 | activerecord (= 7.0.8) 75 | activesupport (= 7.0.8) 76 | marcel (~> 1.0) 77 | mini_mime (>= 1.1.0) 78 | activesupport (7.0.8) 79 | concurrent-ruby (~> 1.0, >= 1.0.2) 80 | i18n (>= 1.6, < 2) 81 | minitest (>= 5.1) 82 | tzinfo (~> 2.0) 83 | addressable (2.8.5) 84 | public_suffix (>= 2.0.2, < 6.0) 85 | aes_key_wrap (1.1.0) 86 | ast (2.4.2) 87 | attr_required (1.0.1) 88 | avo (2.43.0) 89 | actionview (>= 6.0) 90 | active_link_to 91 | activerecord (>= 6.0) 92 | addressable 93 | docile 94 | dry-initializer 95 | httparty 96 | inline_svg 97 | meta-tags 98 | pagy 99 | turbo-rails 100 | view_component (>= 2.54.0) 101 | zeitwerk (>= 2.6.2) 102 | bcrypt (3.1.18) 103 | bindata (2.4.15) 104 | builder (3.2.4) 105 | byebug (11.1.3) 106 | capybara (3.39.2) 107 | addressable 108 | matrix 109 | mini_mime (>= 0.1.3) 110 | nokogiri (~> 1.8) 111 | rack (>= 1.6.0) 112 | rack-test (>= 0.6.3) 113 | regexp_parser (>= 1.5, < 3.0) 114 | xpath (~> 3.2) 115 | coderay (1.1.3) 116 | commonmarker (1.0.4) 117 | rb_sys (~> 0.9) 118 | concurrent-ruby (1.2.2) 119 | crass (1.0.6) 120 | date (3.3.3) 121 | docile (1.4.0) 122 | dry-initializer (3.1.1) 123 | erubi (1.12.0) 124 | eth (0.5.10) 125 | keccak (~> 1.3) 126 | konstructor (~> 1.0) 127 | openssl (>= 2.2, < 4.0) 128 | rbsecp256k1 (~> 5.1) 129 | scrypt (~> 3.0) 130 | execjs (2.8.1) 131 | faraday (2.7.4) 132 | faraday-net_http (>= 2.0, < 3.1) 133 | ruby2_keywords (>= 0.0.4) 134 | faraday-follow_redirects (0.3.0) 135 | faraday (>= 1, < 3) 136 | faraday-net_http (3.0.2) 137 | faraday-retry (2.0.0) 138 | faraday (~> 2.0) 139 | ffi (1.15.5) 140 | ffi-compiler (1.0.1) 141 | ffi (>= 1.0.0) 142 | rake 143 | gapic-common (0.17.1) 144 | faraday (>= 1.9, < 3.a) 145 | faraday-retry (>= 1.0, < 3.a) 146 | google-protobuf (~> 3.14) 147 | googleapis-common-protos (>= 1.3.12, < 2.a) 148 | googleapis-common-protos-types (>= 1.3.1, < 2.a) 149 | googleauth (~> 1.0) 150 | grpc (~> 1.36) 151 | globalid (1.2.1) 152 | activesupport (>= 6.1) 153 | google-cloud-core (1.6.0) 154 | google-cloud-env (~> 1.0) 155 | google-cloud-errors (~> 1.0) 156 | google-cloud-env (1.6.0) 157 | faraday (>= 0.17.3, < 3.0) 158 | google-cloud-error_reporting (0.42.2) 159 | concurrent-ruby (~> 1.1) 160 | google-cloud-core (~> 1.5) 161 | google-cloud-error_reporting-v1beta1 (~> 0.0) 162 | stackdriver-core (~> 1.3) 163 | google-cloud-error_reporting-v1beta1 (0.5.1) 164 | gapic-common (>= 0.16.0, < 2.a) 165 | google-cloud-errors (~> 1.0) 166 | google-cloud-errors (1.3.0) 167 | google-cloud-logging (2.3.2) 168 | concurrent-ruby (~> 1.1) 169 | google-cloud-core (~> 1.5) 170 | google-cloud-logging-v2 (~> 0.0) 171 | stackdriver-core (~> 1.3) 172 | google-cloud-logging-v2 (0.8.1) 173 | gapic-common (>= 0.10, < 2.a) 174 | google-cloud-errors (~> 1.0) 175 | google-cloud-trace (0.42.1) 176 | concurrent-ruby (~> 1.1) 177 | google-cloud-core (~> 1.5) 178 | google-cloud-trace-v1 (~> 0.0) 179 | google-cloud-trace-v2 (~> 0.0) 180 | stackdriver-core (~> 1.3) 181 | google-cloud-trace-v1 (0.4.0) 182 | gapic-common (>= 0.10, < 2.a) 183 | google-cloud-errors (~> 1.0) 184 | google-cloud-trace-v2 (0.4.1) 185 | gapic-common (>= 0.16.0, < 2.a) 186 | google-cloud-errors (~> 1.0) 187 | google-protobuf (3.24.0) 188 | googleapis-common-protos (1.4.0) 189 | google-protobuf (~> 3.14) 190 | googleapis-common-protos-types (~> 1.2) 191 | grpc (~> 1.27) 192 | googleapis-common-protos-types (1.8.0) 193 | google-protobuf (~> 3.18) 194 | googleauth (1.3.0) 195 | faraday (>= 0.17.3, < 3.a) 196 | jwt (>= 1.4, < 3.0) 197 | memoist (~> 0.16) 198 | multi_json (~> 1.11) 199 | os (>= 0.9, < 2.0) 200 | signet (>= 0.16, < 2.a) 201 | graphiql-rails (1.9.0) 202 | railties 203 | sprockets-rails 204 | graphql (2.2.5) 205 | racc (~> 1.4) 206 | grpc (1.57.0) 207 | google-protobuf (~> 3.23) 208 | googleapis-common-protos-types (~> 1.0) 209 | hashie (5.0.0) 210 | httparty (0.21.0) 211 | mini_mime (>= 1.0.0) 212 | multi_xml (>= 0.5.2) 213 | httpclient (2.8.3) 214 | i18n (1.14.1) 215 | concurrent-ruby (~> 1.0) 216 | inline_svg (1.9.0) 217 | activesupport (>= 3.0) 218 | nokogiri (>= 1.6) 219 | jbuilder (2.11.5) 220 | actionview (>= 5.0.0) 221 | activesupport (>= 5.0.0) 222 | json-jwt (1.16.3) 223 | activesupport (>= 4.2) 224 | aes_key_wrap 225 | bindata 226 | faraday (~> 2.0) 227 | faraday-follow_redirects 228 | jwt (2.7.0) 229 | kaminari (1.2.2) 230 | activesupport (>= 4.1.0) 231 | kaminari-actionview (= 1.2.2) 232 | kaminari-activerecord (= 1.2.2) 233 | kaminari-core (= 1.2.2) 234 | kaminari-actionview (1.2.2) 235 | actionview 236 | kaminari-core (= 1.2.2) 237 | kaminari-activerecord (1.2.2) 238 | activerecord 239 | kaminari-core (= 1.2.2) 240 | kaminari-core (1.2.2) 241 | keccak (1.3.1) 242 | konstructor (1.0.2) 243 | listen (3.8.0) 244 | rb-fsevent (~> 0.10, >= 0.10.3) 245 | rb-inotify (~> 0.9, >= 0.9.10) 246 | lograge (0.14.0) 247 | actionpack (>= 4) 248 | activesupport (>= 4) 249 | railties (>= 4) 250 | request_store (~> 1.0) 251 | loofah (2.22.0) 252 | crass (~> 1.0.2) 253 | nokogiri (>= 1.12.0) 254 | mail (2.8.1) 255 | mini_mime (>= 0.1.1) 256 | net-imap 257 | net-pop 258 | net-smtp 259 | marcel (1.0.2) 260 | marked-rails (9.1.2.0) 261 | matrix (0.4.2) 262 | memoist (0.16.2) 263 | meta-tags (2.20.0) 264 | actionpack (>= 6.0.0, < 7.2) 265 | method_source (1.0.0) 266 | mini_mime (1.1.5) 267 | mini_portile2 (2.8.5) 268 | minitest (5.21.1) 269 | multi_json (1.15.0) 270 | multi_xml (0.6.0) 271 | net-imap (0.3.7) 272 | date 273 | net-protocol 274 | net-pop (0.1.2) 275 | net-protocol 276 | net-protocol (0.2.1) 277 | timeout 278 | net-smtp (0.3.3) 279 | net-protocol 280 | nio4r (2.7.0) 281 | nokogiri (1.16.0) 282 | mini_portile2 (~> 2.8.2) 283 | racc (~> 1.4) 284 | omniauth (2.1.1) 285 | hashie (>= 3.4.6) 286 | rack (>= 2.2.3) 287 | rack-protection 288 | omniauth-rails_csrf_protection (1.0.1) 289 | actionpack (>= 4.2) 290 | omniauth (~> 2.0) 291 | omniauth_openid_connect (0.6.1) 292 | omniauth (>= 1.9, < 3) 293 | openid_connect (~> 1.1) 294 | openid_connect (1.4.2) 295 | activemodel 296 | attr_required (>= 1.0.0) 297 | json-jwt (>= 1.15.0) 298 | net-smtp 299 | rack-oauth2 (~> 1.21) 300 | swd (~> 1.3) 301 | tzinfo 302 | validate_email 303 | validate_url 304 | webfinger (~> 1.2) 305 | openssl (3.1.0) 306 | os (1.1.4) 307 | pagy (6.1.0) 308 | parser (3.2.2.1) 309 | ast (~> 2.4.1) 310 | pg (1.5.4) 311 | pkg-config (1.5.1) 312 | pry (0.14.2) 313 | coderay (~> 1.1) 314 | method_source (~> 1.0) 315 | pry-rails (0.3.9) 316 | pry (>= 0.10.4) 317 | psych (5.1.0) 318 | stringio 319 | public_suffix (5.0.3) 320 | puma (6.4.2) 321 | nio4r (~> 2.0) 322 | racc (1.7.3) 323 | rack (2.2.8) 324 | rack-oauth2 (1.21.3) 325 | activesupport 326 | attr_required 327 | httpclient 328 | json-jwt (>= 1.11.0) 329 | rack (>= 2.1.0) 330 | rack-protection (3.0.5) 331 | rack 332 | rack-test (2.1.0) 333 | rack (>= 1.3) 334 | rails (7.0.8) 335 | actioncable (= 7.0.8) 336 | actionmailbox (= 7.0.8) 337 | actionmailer (= 7.0.8) 338 | actionpack (= 7.0.8) 339 | actiontext (= 7.0.8) 340 | actionview (= 7.0.8) 341 | activejob (= 7.0.8) 342 | activemodel (= 7.0.8) 343 | activerecord (= 7.0.8) 344 | activestorage (= 7.0.8) 345 | activesupport (= 7.0.8) 346 | bundler (>= 1.15.0) 347 | railties (= 7.0.8) 348 | rails-dom-testing (2.2.0) 349 | activesupport (>= 5.0.0) 350 | minitest 351 | nokogiri (>= 1.6) 352 | rails-html-sanitizer (1.6.0) 353 | loofah (~> 2.21) 354 | nokogiri (~> 1.14) 355 | rails_12factor (0.0.3) 356 | rails_serve_static_assets 357 | rails_stdout_logging 358 | rails_serve_static_assets (0.0.5) 359 | rails_stdout_logging (0.0.5) 360 | railties (7.0.8) 361 | actionpack (= 7.0.8) 362 | activesupport (= 7.0.8) 363 | method_source 364 | rake (>= 12.2) 365 | thor (~> 1.0) 366 | zeitwerk (~> 2.5) 367 | rake (13.1.0) 368 | rb-fsevent (0.11.2) 369 | rb-inotify (0.10.1) 370 | ffi (~> 1.0) 371 | rb_sys (0.9.86) 372 | rbs (3.1.0) 373 | rbs_rails (0.12.0) 374 | parser 375 | rbs (>= 1) 376 | rbsecp256k1 (5.1.1) 377 | mini_portile2 (~> 2.8) 378 | pkg-config (~> 1.5) 379 | rubyzip (~> 2.3) 380 | rdoc (6.5.0) 381 | psych (>= 4.0.0) 382 | regexp_parser (2.8.1) 383 | request_store (1.5.1) 384 | rack (>= 1.4) 385 | rexml (3.2.6) 386 | ruby2_keywords (0.0.5) 387 | rubyzip (2.3.2) 388 | sass-rails (6.0.0) 389 | sassc-rails (~> 2.1, >= 2.1.1) 390 | sassc (2.4.0) 391 | ffi (~> 1.9) 392 | sassc-rails (2.1.2) 393 | railties (>= 4.0.0) 394 | sassc (>= 2.0) 395 | sprockets (> 3.0) 396 | sprockets-rails 397 | tilt 398 | scrypt (3.0.7) 399 | ffi-compiler (>= 1.0, < 2.0) 400 | sdoc (1.0.0) 401 | rdoc (>= 5.0) 402 | selenium-webdriver (4.14.0) 403 | rexml (~> 3.2, >= 3.2.5) 404 | rubyzip (>= 1.2.2, < 3.0) 405 | websocket (~> 1.0) 406 | signet (0.17.0) 407 | addressable (~> 2.8) 408 | faraday (>= 0.17.5, < 3.a) 409 | jwt (>= 1.5, < 3.0) 410 | multi_json (~> 1.10) 411 | sitemap_generator (6.3.0) 412 | builder (~> 3.0) 413 | siwe (2.0.0) 414 | eth (~> 0.5.1) 415 | slim (5.1.1) 416 | temple (~> 0.10.0) 417 | tilt (>= 2.1.0) 418 | slim-rails (3.6.3) 419 | actionpack (>= 3.1) 420 | railties (>= 3.1) 421 | slim (>= 3.0, < 6.0, != 5.0.0) 422 | sprockets (4.2.0) 423 | concurrent-ruby (~> 1.0) 424 | rack (>= 2.2.4, < 4) 425 | sprockets-rails (3.4.2) 426 | actionpack (>= 5.2) 427 | activesupport (>= 5.2) 428 | sprockets (>= 3.0.0) 429 | stackdriver (0.21.1) 430 | google-cloud-error_reporting (~> 0.41) 431 | google-cloud-logging (~> 2.1) 432 | google-cloud-trace (~> 0.40) 433 | stackdriver-core (1.5.0) 434 | google-cloud-core (~> 1.2) 435 | stringio (3.0.5) 436 | swd (1.3.0) 437 | activesupport (>= 3) 438 | attr_required (>= 0.0.5) 439 | httpclient (>= 2.4) 440 | temple (0.10.3) 441 | thor (1.3.0) 442 | tilt (2.3.0) 443 | timeout (0.4.0) 444 | turbo-rails (1.0.1) 445 | actionpack (>= 6.0.0) 446 | railties (>= 6.0.0) 447 | tzinfo (2.0.6) 448 | concurrent-ruby (~> 1.0) 449 | uglifier (4.2.0) 450 | execjs (>= 0.3.0, < 3) 451 | validate_email (0.1.6) 452 | activemodel (>= 3.0) 453 | mail (>= 2.2.5) 454 | validate_url (1.0.15) 455 | activemodel (>= 3.0.0) 456 | public_suffix 457 | view_component (3.10.0) 458 | activesupport (>= 5.2.0, < 8.0) 459 | concurrent-ruby (~> 1.0) 460 | method_source (~> 1.0) 461 | webfinger (1.2.0) 462 | activesupport 463 | httpclient (>= 2.4) 464 | websocket (1.2.10) 465 | websocket-driver (0.7.6) 466 | websocket-extensions (>= 0.1.0) 467 | websocket-extensions (0.1.5) 468 | xpath (3.2.0) 469 | nokogiri (~> 1.8) 470 | zeitwerk (2.6.12) 471 | 472 | PLATFORMS 473 | ruby 474 | 475 | DEPENDENCIES 476 | avo 477 | byebug 478 | capybara 479 | commonmarker 480 | graphiql-rails 481 | graphql 482 | jbuilder 483 | kaminari 484 | listen 485 | lograge 486 | marked-rails 487 | meta-tags 488 | omniauth-rails_csrf_protection 489 | omniauth-siwe! 490 | pg 491 | pry-rails 492 | puma 493 | rails (~> 7.0.0) 494 | rails_12factor 495 | rbs_rails 496 | sass-rails 497 | sdoc (~> 1.0.0) 498 | selenium-webdriver 499 | sitemap_generator 500 | slim-rails 501 | stackdriver 502 | turbo-rails (~> 1.0.0) 503 | uglifier 504 | 505 | BUNDLED WITH 506 | 2.1.4 507 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Kenichi Takahashi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | == README 2 | 3 | This README would normally document whatever steps are necessary to get the 4 | application up and running. 5 | 6 | Things you may want to cover: 7 | 8 | * Ruby version 9 | 10 | * System dependencies 11 | 12 | * Configuration 13 | 14 | * Database creation 15 | 16 | * Database initialization 17 | 18 | * How to run the test suite 19 | 20 | * Services (job queues, cache servers, search engines, etc.) 21 | 22 | * Deployment instructions 23 | 24 | * ... 25 | 26 | 27 | Please feel free to use a different markup language if you do not plan to run 28 | rake doc:app. 29 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative 'config/application' 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /Steepfile: -------------------------------------------------------------------------------- 1 | target :app do 2 | check "app/models" 3 | signature "sig" 4 | repo_path "vendor/rbs/gem_rbs_collection/gems" 5 | 6 | library 'pathname' 7 | library 'logger' 8 | library 'mutex_m' 9 | library 'date' 10 | library 'monitor' 11 | library 'singleton' 12 | library 'tsort' 13 | library 'securerandom' 14 | library 'base64' 15 | library 'forwardable' 16 | library 'time' 17 | library 'json' 18 | 19 | library 'rack' 20 | 21 | library 'activesupport' 22 | library 'actionpack' 23 | library 'activejob' 24 | library 'activemodel' 25 | library 'actionview' 26 | library 'activerecord' 27 | library 'railties' 28 | end 29 | -------------------------------------------------------------------------------- /app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../javascripts .js 3 | //= link_directory ../stylesheets .css 4 | -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/app/assets/images/.keep -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's 5 | // vendor/assets/javascripts directory can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. JavaScript code in this file should be added after the last require_* statement. 9 | // 10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require rails-ujs 14 | //= require_tree . 15 | -------------------------------------------------------------------------------- /app/assets/stylesheets/_articles.scss: -------------------------------------------------------------------------------- 1 | .article-grid-card { 2 | height: 30rem; 3 | overflow: hidden; 4 | color: var(--base-font-color); 5 | } 6 | .mdc-card .card-header, .card-text { 7 | padding: 0rem 1rem; 8 | } 9 | .right { 10 | text-align: right; 11 | } 12 | -------------------------------------------------------------------------------- /app/assets/stylesheets/_base.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --mdc-typography-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Hiragino Sans', 'BIZ UDPGothic', sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Sans Emoji"; 3 | --mdc-typography-body2-line-height: 1.5rem; 4 | --mdc-theme-primary: #003529; 5 | 6 | --base-font-color: #333; 7 | --link-text-color: #1D7FAF; 8 | --link-text-color__hover: #62A3C4; 9 | } 10 | 11 | .mdc-top-app-bar__title a { 12 | color: white; 13 | &:hover { 14 | color: #CCCCCC; 15 | } 16 | } 17 | 18 | body { 19 | color: var(--base-font-color); 20 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Hiragino Sans', 'BIZ UDPGothic', sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Sans Emoji"; 21 | margin: 0; 22 | line-height: 1.5rem; 23 | } 24 | 25 | img, embed, object, video { 26 | max-width: 100%; 27 | } 28 | 29 | footer { 30 | width: 100%; 31 | height: 20px; 32 | } 33 | 34 | a { 35 | overflow-wrap: break-word; 36 | color: var(--link-text-color); 37 | text-decoration: none; 38 | transition: 0.3s; 39 | &:hover { 40 | color: var(--link-text-color__hover); 41 | } 42 | } 43 | 44 | .pagination { 45 | margin: 1rem; 46 | font-size: large; 47 | } 48 | 49 | .main-article { 50 | margin: 0px auto; 51 | width: 100%; 52 | 53 | @media screen and (min-width: 768px) { 54 | width: 600px; 55 | } 56 | @media screen and (min-width: 1025px) { 57 | width: 800px; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/assets/stylesheets/admin/articles.scss: -------------------------------------------------------------------------------- 1 | code { 2 | background-color: #f0f0f0; 3 | padding: 0.2em; 4 | border-radius: 4px; 5 | font-family: monospace, "Noto Sans", "Noto Sans CJK JP", sans-serif; 6 | } 7 | pre > code { 8 | display: block; 9 | border: none; 10 | line-height: 1.6em; 11 | padding: 0.5em; 12 | overflow-x: auto; 13 | } 14 | 15 | .site_header { 16 | z-index: 100; 17 | top: 0; 18 | position: sticky; 19 | height: 3.5rem; 20 | border-bottom: 1px solid #cacaca; 21 | color: #1a455a; 22 | background: #dfebfd; 23 | font-weight: 700; 24 | display: flex; 25 | align-items: center; 26 | } 27 | .site_header__title { 28 | margin: 0 auto 0; 29 | font-size: 1.2rem; 30 | text-decoration: none; 31 | color: inherit; 32 | } 33 | .article { 34 | border-top: 1px solid #bbb; 35 | margin-bottom: 1rem; 36 | } 37 | main .article:first-child { 38 | border: none; 39 | } 40 | .article__title { 41 | margin-top: 0; 42 | padding-top: 0; 43 | font-size: 1.7rem; 44 | font-weight: 700; 45 | line-height: 2.5rem; 46 | } 47 | .article__published_on { 48 | padding: 0; 49 | font-size: 0.75rem; 50 | color: #777; 51 | } 52 | .article__body { 53 | margin-top: 1.5rem; 54 | margin-bottom: 2rem; 55 | color: #545454; 56 | line-height: 1.7em; 57 | } 58 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.scss: -------------------------------------------------------------------------------- 1 | @import "base"; 2 | @import "articles"; 3 | -------------------------------------------------------------------------------- /app/avo/resources/article_resource.rb: -------------------------------------------------------------------------------- 1 | class ArticleResource < Avo::BaseResource 2 | self.title = :id 3 | self.includes = [] 4 | # self.search_query = ->(params:) do 5 | # scope.ransack(id_eq: params[:q], m: "or").result(distinct: false) 6 | # end 7 | 8 | field :id, as: :id 9 | field :title, as: :text, format_using: -> (value) { value&.truncate 20 } 10 | field :body, as: :markdown 11 | field :slug, as: :text 12 | field :published_on, as: :date 13 | field :draft, as: :boolean 14 | field :featured_image_url, as: :external_image 15 | # add fields here 16 | end 17 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery with: :exception 3 | end 4 | -------------------------------------------------------------------------------- /app/controllers/articles_controller.rb: -------------------------------------------------------------------------------- 1 | class ArticlesController < ApplicationController 2 | layout 'application' 3 | 4 | def index 5 | @articles = Article.published.order(published_on: :desc).page(params[:page]).per(params[:per_page] || 12) 6 | end 7 | 8 | def show 9 | if params[:year] 10 | year, month, day = params.values_at(:year, :month, :day).map(&:to_i) 11 | slug = params[:slug] 12 | @article = Article.published.where(published_on: Date.new(year, month, day), slug: slug).first! 13 | 14 | redirect_to article_path(title: @article.title), status: 301 15 | return 16 | end 17 | 18 | @article = Article.published.where(title: params[:title]).first! 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /app/controllers/avo/articles_controller.rb: -------------------------------------------------------------------------------- 1 | class Avo::ArticlesController < Avo::ResourcesController 2 | end 3 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /app/controllers/graphql_controller.rb: -------------------------------------------------------------------------------- 1 | class GraphqlController < ApplicationController 2 | protect_from_forgery with: :null_session 3 | 4 | def execute 5 | variables = ensure_hash(params[:variables]) 6 | query = params[:query] 7 | operation_name = params[:operationName] 8 | context = { 9 | # Query context goes here, for example: 10 | # current_user: current_user, 11 | } 12 | result = TdnmSchema.execute(query, variables: variables, context: context, operation_name: operation_name) 13 | render json: result 14 | rescue => e 15 | raise e unless Rails.env.development? 16 | handle_error_in_development e 17 | end 18 | 19 | private 20 | 21 | # Handle form data, JSON body, or a blank value 22 | def ensure_hash(ambiguous_param) 23 | case ambiguous_param 24 | when String 25 | if ambiguous_param.present? 26 | ensure_hash(JSON.parse(ambiguous_param)) 27 | else 28 | {} 29 | end 30 | when Hash, ActionController::Parameters 31 | ambiguous_param 32 | when nil 33 | {} 34 | else 35 | raise ArgumentError, "Unexpected parameter: #{ambiguous_param}" 36 | end 37 | end 38 | 39 | def handle_error_in_development(e) 40 | logger.error e.message 41 | logger.error e.backtrace.join("\n") 42 | 43 | render json: { error: { message: e.message, backtrace: e.backtrace }, data: {} }, status: 500 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /app/controllers/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class SessionsController < ApplicationController 2 | def new 3 | end 4 | 5 | def create 6 | reset_session 7 | 8 | session[:user_id] = request.env['omniauth.auth']['uid'] 9 | 10 | redirect_to '/avo' 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/graphql/mutations/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/app/graphql/mutations/.keep -------------------------------------------------------------------------------- /app/graphql/tdnm_schema.rb: -------------------------------------------------------------------------------- 1 | class TdnmSchema < GraphQL::Schema 2 | mutation(Types::MutationType) 3 | query(Types::QueryType) 4 | end 5 | -------------------------------------------------------------------------------- /app/graphql/types/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/app/graphql/types/.keep -------------------------------------------------------------------------------- /app/graphql/types/article_type.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | class ArticleType < Types::BaseObject 3 | field :id, ID, null: false 4 | field :title, String, null: false 5 | field :body, String, null: false 6 | field :slug, String, null: false 7 | field :published_on, GraphQL::Types::ISO8601DateTime, null: false 8 | field :created_at, GraphQL::Types::ISO8601DateTime, null: false 9 | field :updated_at, GraphQL::Types::ISO8601DateTime, null: false 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/graphql/types/base_enum.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | class BaseEnum < GraphQL::Schema::Enum 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/graphql/types/base_input_object.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | class BaseInputObject < GraphQL::Schema::InputObject 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/graphql/types/base_interface.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | module BaseInterface 3 | include GraphQL::Schema::Interface 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/graphql/types/base_object.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | class BaseObject < GraphQL::Schema::Object 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/graphql/types/base_scalar.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | class BaseScalar < GraphQL::Schema::Scalar 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/graphql/types/base_union.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | class BaseUnion < GraphQL::Schema::Union 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/graphql/types/mutation_type.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | class MutationType < Types::BaseObject 3 | # TODO: remove me 4 | field :test_field, String, null: false, 5 | description: "An example field added by the generator" 6 | def test_field 7 | "Hello World" 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/graphql/types/query_type.rb: -------------------------------------------------------------------------------- 1 | module Types 2 | class QueryType < Types::BaseObject 3 | # Add root-level fields here. 4 | # They will be entry points for queries on your schema. 5 | 6 | field :article, Types::ArticleType, null: true do 7 | description 'Find a article' 8 | argument :id, ID, required: false 9 | argument :slug, String, required: false 10 | end 11 | 12 | field :articles, Types::ArticleType.connection_type, null: false, max_page_size: 100 do 13 | description 'List articles' 14 | argument :published_on, String, required: false 15 | end 16 | 17 | def article(id: nil, slug: nil) 18 | if id 19 | Article.find(id) 20 | else 21 | Article.where(title: slug).first 22 | end 23 | end 24 | 25 | def articles(published_on: nil) 26 | if published_on 27 | Article.where(published_on: published_on) 28 | else 29 | Article.order(published_on: :desc) 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | def weblog 3 | @_weblog ||= Weblog.first 4 | end 5 | 6 | def meta_description 7 | @_meta_description ||= if @article 8 | truncate( 9 | strip_tags(Commonmarker.to_html(@article.body)), 10 | length: MetaTags.config.description_limit 11 | ) 12 | else 13 | nil 14 | end 15 | end 16 | 17 | def default_meta_tags 18 | { 19 | site: weblog.title, 20 | charset: 'utf-8', 21 | title: @article.try(:title), 22 | reverse: true, 23 | description: meta_description, 24 | og: { 25 | title: @article.try(:title), 26 | site_name: weblog.title, 27 | image: @article.try(:featured_image_url).blank? ? weblog.default_featured_image_url : @article.featured_image_url, 28 | description: meta_description, 29 | url: @article ? article_path(title: @article.title, only_path: false) : root_url(only_path: false), 30 | type: @article ? 'article' : 'website' 31 | }, 32 | twitter: { 33 | card: "summary" 34 | } 35 | } 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /app/helpers/articles_helper.rb: -------------------------------------------------------------------------------- 1 | module ArticlesHelper 2 | 3 | end 4 | -------------------------------------------------------------------------------- /app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | end 3 | -------------------------------------------------------------------------------- /app/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/app/mailers/.keep -------------------------------------------------------------------------------- /app/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/app/models/.keep -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | end 4 | -------------------------------------------------------------------------------- /app/models/article.rb: -------------------------------------------------------------------------------- 1 | class Article < ApplicationRecord 2 | scope :published, -> { where(draft: false) } 3 | scope :drafts, -> { where(draft: true) } 4 | end 5 | -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/app/models/concerns/.keep -------------------------------------------------------------------------------- /app/models/weblog.rb: -------------------------------------------------------------------------------- 1 | class Weblog < ApplicationRecord 2 | end 3 | -------------------------------------------------------------------------------- /app/views/articles/index.atom.builder: -------------------------------------------------------------------------------- 1 | atom_feed(language: 'ja_JP') do |feed| 2 | feed.title(weblog.title) 3 | feed.updated(@articles[0].created_at) if @articles.length > 0 4 | 5 | @articles.each do |a| 6 | feed.entry(a, url: article_url(title: a.title, only_path: false)) do |entry| 7 | entry.title(a.title) 8 | entry.content( 9 | (a.featured_image_url.present? ? "" : '') + 10 | Commonmarker.to_html(a.body, options: { render: { unsafe: true } }), type: 'html' 11 | ) 12 | 13 | entry.author do |author| 14 | author.name("Kenichi TAKAHASHI") 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/views/articles/index.html.slim: -------------------------------------------------------------------------------- 1 | .mdc-layout-grid 2 | .mdc-layout-grid__inner 3 | - @articles.each do |a| 4 | .mdc-layout-grid__cell--span-4 5 | a href="#{article_path(title: a.title)}" 6 | article.mdc-card.article-grid-card.mdc-ripple-surface.mdc-elevation--z3 7 | header.card-header 8 | h2= a.title 9 | - if a.featured_image_url? 10 | .mdc-card__media.mdc-card__media--16-9 style="background-image: url(#{a.featured_image_url});" 11 | 12 | .card-text== sanitize(Commonmarker.to_html(a.body, options: { render: { unsafe: true} }), tags: %w(p br)) 13 | .mdc-layout-grid__inner 14 | .mdc-layout-grid__cell--span-12 style="display: flex; justify-content: center;" 15 | = paginate @articles 16 | -------------------------------------------------------------------------------- /app/views/articles/show.html.slim: -------------------------------------------------------------------------------- 1 | .mdc-layout-grid.main-article 2 | .mdc-layout-grid__inner 3 | .mdc-layout-grid__cell--span-4-phone.mdc-layout-grid__cell--span-12-desktop.mdc-layout-grid__cell--span-8-tablet.mdc-elevation--z3 4 | article.mdc-card 5 | header.card-header 6 | h2= @article.title 7 | - if @article.featured_image_url? 8 | .mdc-card__media.mdc-card__media--16-9 style="background-image: url(#{@article.featured_image_url});" 9 | 10 | .card-text 11 | == Commonmarker.to_html(@article.body, options: { render: { unsafe: true} }) 12 | .right 13 | = "created_at: " 14 | == @article.created_at 15 | .right 16 | = "updated_at: " 17 | == @article.created_at 18 | -------------------------------------------------------------------------------- /app/views/kaminari/_first_page.html.slim: -------------------------------------------------------------------------------- 1 | / Link to the "First" page 2 | - available local variables 3 | url : url to the first page 4 | current_page : a page object for the currently displayed page 5 | total_pages : total number of pages 6 | per_page : number of items to fetch per page 7 | remote : data-remote 8 | span.first 9 | == link_to_unless current_page.first?, t('views.pagination.first').html_safe, url, :remote => remote 10 | ' 11 | -------------------------------------------------------------------------------- /app/views/kaminari/_gap.html.slim: -------------------------------------------------------------------------------- 1 | / Non-link tag that stands for skipped pages... 2 | - available local variables 3 | current_page : a page object for the currently displayed page 4 | total_pages : total number of pages 5 | per_page : number of items to fetch per page 6 | remote : data-remote 7 | span.page.gap 8 | == t('views.pagination.truncate').html_safe 9 | ' 10 | -------------------------------------------------------------------------------- /app/views/kaminari/_last_page.html.slim: -------------------------------------------------------------------------------- 1 | / Link to the "Last" page 2 | - available local variables 3 | url : url to the last page 4 | current_page : a page object for the currently displayed page 5 | total_pages : total number of pages 6 | per_page : number of items to fetch per page 7 | remote : data-remote 8 | span.last 9 | == link_to_unless current_page.last?, t('views.pagination.last').html_safe, url, :remote => remote 10 | ' 11 | -------------------------------------------------------------------------------- /app/views/kaminari/_next_page.html.slim: -------------------------------------------------------------------------------- 1 | / Link to the "Next" page 2 | - available local variables 3 | url : url to the next page 4 | current_page : a page object for the currently displayed page 5 | total_pages : total number of pages 6 | per_page : number of items to fetch per page 7 | remote : data-remote 8 | span.next 9 | == link_to_unless current_page.last?, t('views.pagination.next').html_safe, url, :rel => 'next', :remote => remote 10 | ' 11 | -------------------------------------------------------------------------------- /app/views/kaminari/_page.html.slim: -------------------------------------------------------------------------------- 1 | / Link showing page number 2 | - available local variables 3 | page : a page object for "this" page 4 | url : url to this page 5 | current_page : a page object for the currently displayed page 6 | total_pages : total number of pages 7 | per_page : number of items to fetch per page 8 | remote : data-remote 9 | span class="page#{' current' if page.current?}" 10 | == link_to_unless page.current?, page, url, {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil} 11 | ' 12 | -------------------------------------------------------------------------------- /app/views/kaminari/_paginator.html.slim: -------------------------------------------------------------------------------- 1 | / The container tag 2 | - available local variables 3 | current_page : a page object for the currently displayed page 4 | total_pages : total number of pages 5 | per_page : number of items to fetch per page 6 | remote : data-remote 7 | paginator : the paginator that renders the pagination tags inside 8 | 9 | == paginator.render do 10 | nav.pagination 11 | == first_page_tag unless current_page.first? 12 | == prev_page_tag unless current_page.first? 13 | - each_page do |page| 14 | - if page.left_outer? || page.right_outer? || page.inside_window? 15 | == page_tag page 16 | - elsif !page.was_truncated? 17 | == gap_tag 18 | == next_page_tag unless current_page.last? 19 | == last_page_tag unless current_page.last? 20 | -------------------------------------------------------------------------------- /app/views/kaminari/_prev_page.html.slim: -------------------------------------------------------------------------------- 1 | / Link to the "Previous" page 2 | - available local variables 3 | url : url to the previous page 4 | current_page : a page object for the currently displayed page 5 | total_pages : total number of pages 6 | per_page : number of items to fetch per page 7 | remote : data-remote 8 | span.prev 9 | == link_to_unless current_page.first?, t('views.pagination.previous').html_safe, url, :rel => 'prev', :remote => remote 10 | ' 11 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.slim: -------------------------------------------------------------------------------- 1 | doctype html 2 | 3 | html 4 | head 5 | = display_meta_tags default_meta_tags 6 | meta http-equiv='X-UA-Compatible' content='IE=edge;chrome=1' 7 | meta name='viewport' content='width=device-width, initial-scale=1.0' 8 | 9 | link rel='alternate' type='application/atom+xml' title='atom' href='/atom.xml' 10 | 11 | link href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css" rel="stylesheet" 12 | script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js" 13 | 14 | link rel="stylesheet" href='https://cdnjs.cloudflare.com/ajax/libs/prism/1.23.0/themes/prism.min.css' 15 | script async=true src='https://cdnjs.cloudflare.com/ajax/libs/prism/1.23.0/components/prism-core.min.js' 16 | script async=true src='https://cdnjs.cloudflare.com/ajax/libs/prism/1.23.0/plugins/autoloader/prism-autoloader.min.js' 17 | 18 | = stylesheet_link_tag 'application', media: 'all' 19 | = turbo_include_tags 20 | 21 | body 22 | #root 23 | header.mdc-top-app-bar.mdc-top-app-bar--fixed 24 | .mdc-top-app-bar__row 25 | section.mdc-top-app-bar__section 26 | .mdc-top-app-bar__title= link_to weblog.title, root_path 27 | main.mdc-top-app-bar--fixed-adjust 28 | == yield 29 | footer 30 | -------------------------------------------------------------------------------- /app/views/sessions/new.html.slim: -------------------------------------------------------------------------------- 1 | - if flash[:notice] 2 | = flash[:notice] 3 | 4 | = form_tag '/auth/siwe', method: 'post', data: {turbo: false} 5 | = submit_tag 'Sign-in With Ethereum' 6 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path("../config/application", __dir__) 3 | require_relative "../config/boot" 4 | require "rails/commands" 5 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative "../config/boot" 3 | require "rake" 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /bin/render-build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # exit on error 3 | set -o errexit 4 | 5 | bundle install --deployment 6 | bundle exec rake assets:precompile 7 | bundle exec rake assets:clean 8 | bundle exec rake db:migrate 9 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "fileutils" 3 | 4 | # path to your application root. 5 | APP_ROOT = File.expand_path("..", __dir__) 6 | 7 | def system!(*args) 8 | system(*args) || abort("\n== Command #{args} failed ==") 9 | end 10 | 11 | FileUtils.chdir APP_ROOT do 12 | # This script is a way to set up or update your development environment automatically. 13 | # This script is idempotent, so that you can run it at any time and get an expectable outcome. 14 | # Add necessary setup steps to this file. 15 | 16 | puts "== Installing dependencies ==" 17 | system! "gem install bundler --conservative" 18 | system("bundle check") || system!("bundle install") 19 | 20 | # puts "\n== Copying sample files ==" 21 | # unless File.exist?("config/database.yml") 22 | # FileUtils.cp "config/database.yml.sample", "config/database.yml" 23 | # end 24 | 25 | puts "\n== Preparing database ==" 26 | system! "bin/rails db:prepare" 27 | 28 | puts "\n== Removing old logs and tempfiles ==" 29 | system! "bin/rails log:clear tmp:clear" 30 | 31 | puts "\n== Restarting application server ==" 32 | system! "bin/rails restart" 33 | end 34 | -------------------------------------------------------------------------------- /bin/start: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -xe 4 | 5 | bin/rails assets:precompile; 6 | bin/rails db:migrate 7 | 8 | bin/rails s -b 0.0.0.0; 9 | -------------------------------------------------------------------------------- /bin/steep: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | load Gem.bin_path('steep', 'steep') 3 | -------------------------------------------------------------------------------- /bin/yarn: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_ROOT = File.expand_path('..', __dir__) 3 | Dir.chdir(APP_ROOT) do 4 | yarn = ENV["PATH"].split(File::PATH_SEPARATOR). 5 | select { |dir| File.expand_path(dir) != __dir__ }. 6 | product(["yarn", "yarn.cmd", "yarn.ps1"]). 7 | map { |dir, file| File.expand_path(file, dir) }. 8 | find { |file| File.executable?(file) } 9 | 10 | if yarn 11 | exec yarn, *ARGV 12 | else 13 | $stderr.puts "Yarn executable was not detected in the system." 14 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" 15 | exit 1 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative "config/environment" 4 | 5 | run Rails.application 6 | Rails.application.load_server 7 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative "boot" 2 | 3 | require "rails/all" 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups) 8 | 9 | module Tdnm 10 | class Application < Rails::Application 11 | # Initialize configuration defaults for originally generated Rails version. 12 | config.load_defaults 7.0 13 | 14 | # Configuration for the application, engines, and railties goes here. 15 | # 16 | # These settings can be overridden in specific environments using the files 17 | # in config/environments, which are processed later. 18 | # 19 | config.time_zone = "Tokyo" 20 | config.active_record.default_timezone = :local 21 | # config.eager_load_paths << Rails.root.join("extras") 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) 2 | 3 | require "bundler/setup" # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: redis 3 | url: redis://localhost:6379/1 4 | 5 | test: 6 | adapter: test 7 | 8 | production: 9 | adapter: redis 10 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> 11 | channel_prefix: tdnm_production 12 | -------------------------------------------------------------------------------- /config/credentials.yml.enc: -------------------------------------------------------------------------------- 1 | EMG+s1OHyq/26v+33qI2Gpvlb22TvGKBScyBxm9OdUR3iZSWx8a0GoDRQ62tRMecMkxXUFeCb1hc5HmJEkwU/rd21haF5RmOKmgAviVuYM5cp0y5uc+1DKf1E0+KLoe9JLM6ykJxwh7+OZTa07/q5bul728tNmuEDlW14jE7jp61q6C6L/k/QOfW9IZvTN6/SagGwu+NXuBquJZsm4qzo8YMcp/2Lq5zTaY8qEz2VsrqAwFlcVU0r9G63BPxlSs6P8dNkOVwpw6ePPklsNfHsD26w+WIKRy1zCToanVpzIYQoqZKRuobwQ0P5l6Kl8VcLTwa4ZtweEOXVh+P5FN9kyLdrod62h2OmegDrTbcm0TcDoZKORtifNdBB14/Xg9OLiEdtIpJuGxX4BT/6fgNAlRGZixiCU58qQP008Qrc5KVA+Gz5e5bE213f+UXj/LD1uKP3a41xfHlAijlZBmTVQcCb7ab7Ka1rAG2N5LPs1/ko13mWKBQBQQoRIKTQ3i93omMB2D0iv5xNrkBfcjkDGfLLb9F9xcy+E7ATLaO7vjk0aVMCt2/yR4Ibd+dAIaOjSifja4ydmYoNMe5KgNf3A0C3oPo5aMbLb298SxoHVqnRdxzxYWVAlb09B9EdiTKOtFTr03F+hsESdXIrK4u40X4h1iEbTy4leqDL+JyaiYy/D6Q8f1G0GR6sNbS8UNQ0bDXO41+/IlWBHv64SaZNeCUddMpeLWfqWBWR1vGkniecLXgfvA7pg/OnnUQbsLl7P9kt7i0d3AYC/9LfgWWHQ==--dGMdh9kGtUuR1ZwL--FRXruT78ATH56ZTdo3Qjhg== -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: postgresql 9 | username: <%= ENV.fetch('DATABASE_USERNAME', 'postgres') %> 10 | password: <%= ENV.fetch('DATABASE_PASSWORD', '') %> 11 | host: <%= ENV.fetch('DATABASE_HOST', '127.0.0.1') %> 12 | port: <%= ENV.fetch('DATABASE_PORT', '5432') %> 13 | pool: 5 14 | timeout: 5000 15 | encoding: UTF8 16 | 17 | development: 18 | <<: *default 19 | database: tdnm 20 | 21 | # Warning: The database defined as "test" will be erased and 22 | # re-generated from your development database when you run "rake". 23 | # Do not set this db to the same as development or production. 24 | test: 25 | <<: *default 26 | database: tdnm_test 27 | 28 | production: 29 | <<: *default 30 | database: tdnm_production 31 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative "application" 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # In the development environment your application's code is reloaded any time 7 | # it changes. This slows down response time but is perfect for development 8 | # since you don't have to restart the web server when you make code changes. 9 | config.cache_classes = false 10 | 11 | # Do not eager load code on boot. 12 | config.eager_load = false 13 | 14 | # Show full error reports. 15 | config.consider_all_requests_local = true 16 | 17 | # Enable/disable caching. By default caching is disabled. 18 | # Run rails dev:cache to toggle caching. 19 | if Rails.root.join("tmp/caching-dev.txt").exist? 20 | config.action_controller.perform_caching = true 21 | config.action_controller.enable_fragment_cache_logging = true 22 | 23 | config.cache_store = :memory_store 24 | config.public_file_server.headers = { 25 | "Cache-Control" => "public, max-age=#{2.days.to_i}" 26 | } 27 | else 28 | config.action_controller.perform_caching = false 29 | 30 | config.cache_store = :null_store 31 | end 32 | 33 | # Store uploaded files on the local file system (see config/storage.yml for options). 34 | config.active_storage.service = :local 35 | 36 | # Don't care if the mailer can't send. 37 | config.action_mailer.raise_delivery_errors = false 38 | 39 | config.action_mailer.perform_caching = false 40 | 41 | # Print deprecation notices to the Rails logger. 42 | config.active_support.deprecation = :log 43 | 44 | # Raise exceptions for disallowed deprecations. 45 | config.active_support.disallowed_deprecation = :raise 46 | 47 | # Tell Active Support which deprecation messages to disallow. 48 | config.active_support.disallowed_deprecation_warnings = [] 49 | 50 | # Raise an error on page load if there are pending migrations. 51 | config.active_record.migration_error = :page_load 52 | 53 | # Highlight code that triggered database queries in logs. 54 | config.active_record.verbose_query_logs = true 55 | 56 | # Suppress logger output for asset requests. 57 | config.assets.quiet = true 58 | 59 | # Raises error for missing translations. 60 | # config.i18n.raise_on_missing_translations = true 61 | 62 | # Annotate rendered view with file names. 63 | # config.action_view.annotate_rendered_view_with_filenames = true 64 | 65 | # Uncomment if you wish to allow Action Cable access from any origin. 66 | # config.action_cable.disable_request_forgery_protection = true 67 | end 68 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # Code is not reloaded between requests. 7 | config.cache_classes = true 8 | 9 | # Eager load code on boot. This eager loads most of Rails and 10 | # your application in memory, allowing both threaded web servers 11 | # and those relying on copy on write to perform better. 12 | # Rake tasks automatically ignore this option for performance. 13 | config.eager_load = true 14 | 15 | # Full error reports are disabled and caching is turned on. 16 | config.consider_all_requests_local = false 17 | config.action_controller.perform_caching = true 18 | 19 | # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] 20 | # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). 21 | # config.require_master_key = true 22 | 23 | # Disable serving static files from the `/public` folder by default since 24 | # Apache or NGINX already handles this. 25 | config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? 26 | 27 | # Compress CSS using a preprocessor. 28 | # config.assets.css_compressor = :sass 29 | 30 | # Do not fallback to assets pipeline if a precompiled asset is missed. 31 | config.assets.compile = false 32 | 33 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 34 | # config.asset_host = "http://assets.example.com" 35 | 36 | # Specifies the header that your server uses for sending files. 37 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache 38 | # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX 39 | 40 | # Store uploaded files on the local file system (see config/storage.yml for options). 41 | config.active_storage.service = :local 42 | 43 | # Mount Action Cable outside main process or domain. 44 | # config.action_cable.mount_path = nil 45 | # config.action_cable.url = "wss://example.com/cable" 46 | # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] 47 | 48 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 49 | # config.force_ssl = true 50 | 51 | # Include generic and useful information about system operation, but avoid logging too much 52 | # information to avoid inadvertent exposure of personally identifiable information (PII). 53 | config.log_level = :info 54 | 55 | # Prepend all log lines with the following tags. 56 | config.log_tags = [ :request_id ] 57 | 58 | # Use a different cache store in production. 59 | # config.cache_store = :mem_cache_store 60 | 61 | # Use a real queuing backend for Active Job (and separate queues per environment). 62 | # config.active_job.queue_adapter = :resque 63 | # config.active_job.queue_name_prefix = "tdnm_production" 64 | 65 | config.action_mailer.perform_caching = false 66 | 67 | # Ignore bad email addresses and do not raise email delivery errors. 68 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 69 | # config.action_mailer.raise_delivery_errors = false 70 | 71 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 72 | # the I18n.default_locale when a translation cannot be found). 73 | config.i18n.fallbacks = true 74 | 75 | # Don't log any deprecations. 76 | config.active_support.report_deprecations = false 77 | 78 | # Use default logging formatter so that PID and timestamp are not suppressed. 79 | config.log_formatter = ::Logger::Formatter.new 80 | 81 | # Use a different logger for distributed setups. 82 | # require "syslog/logger" 83 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") 84 | 85 | if ENV["RAILS_LOG_TO_STDOUT"].present? 86 | logger = ActiveSupport::Logger.new(STDOUT) 87 | logger.formatter = config.log_formatter 88 | config.logger = ActiveSupport::TaggedLogging.new(logger) 89 | end 90 | 91 | # Do not dump schema after migrations. 92 | config.active_record.dump_schema_after_migration = false 93 | 94 | # Inserts middleware to perform automatic connection switching. 95 | # The `database_selector` hash is used to pass options to the DatabaseSelector 96 | # middleware. The `delay` is used to determine how long to wait after a write 97 | # to send a subsequent read to the primary. 98 | # 99 | # The `database_resolver` class is used by the middleware to determine which 100 | # database is appropriate to use based on the time delay. 101 | # 102 | # The `database_resolver_context` class is used by the middleware to set 103 | # timestamps for the last write to the primary. The resolver uses the context 104 | # class timestamps to determine how long to wait before reading from the 105 | # replica. 106 | # 107 | # By default Rails will store a last write timestamp in the session. The 108 | # DatabaseSelector middleware is designed as such you can define your own 109 | # strategy for connection switching and pass that into the middleware through 110 | # these configuration options. 111 | # config.active_record.database_selector = { delay: 2.seconds } 112 | # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver 113 | # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session 114 | 115 | # lograge 116 | config.lograge.enabled = true 117 | config.lograge.formatter = Lograge::Formatters::Raw.new 118 | 119 | # Stackdriver Shared parameters 120 | config.google_cloud.project_id = ENV['GOOGLE_CLOUD_PROJECT_ID'] 121 | config.google_cloud.keyfile = ENV['GOOGLE_CLOUD_KEYFILE_PATH'] 122 | config.google_cloud.logging.log_name = 'tdnm_app' 123 | end 124 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | # The test environment is used exclusively to run your application's 4 | # test suite. You never need to work with it otherwise. Remember that 5 | # your test database is "scratch space" for the test suite and is wiped 6 | # and recreated between test runs. Don't rely on the data there! 7 | 8 | Rails.application.configure do 9 | # Settings specified here will take precedence over those in config/application.rb. 10 | 11 | # Turn false under Spring and add config.action_view.cache_template_loading = true 12 | config.cache_classes = true 13 | 14 | # Do not eager load code on boot. This avoids loading your whole application 15 | # just for the purpose of running a single test. If you are using a tool that 16 | # preloads Rails for running tests, you may have to set it to true. 17 | config.eager_load = false 18 | 19 | # Configure public file server for tests with Cache-Control for performance. 20 | config.public_file_server.enabled = true 21 | config.public_file_server.headers = { 22 | "Cache-Control" => "public, max-age=#{1.hour.to_i}" 23 | } 24 | 25 | # Show full error reports and disable caching. 26 | config.consider_all_requests_local = true 27 | config.action_controller.perform_caching = false 28 | config.cache_store = :null_store 29 | 30 | # Raise exceptions instead of rendering exception templates. 31 | config.action_dispatch.show_exceptions = false 32 | 33 | # Disable request forgery protection in test environment. 34 | config.action_controller.allow_forgery_protection = false 35 | 36 | # Store uploaded files on the local file system in a temporary directory. 37 | config.active_storage.service = :test 38 | 39 | config.action_mailer.perform_caching = false 40 | 41 | # Tell Action Mailer not to deliver emails to the real world. 42 | # The :test delivery method accumulates sent emails in the 43 | # ActionMailer::Base.deliveries array. 44 | config.action_mailer.delivery_method = :test 45 | 46 | # Print deprecation notices to the stderr. 47 | config.active_support.deprecation = :stderr 48 | 49 | # Raise exceptions for disallowed deprecations. 50 | config.active_support.disallowed_deprecation = :raise 51 | 52 | # Tell Active Support which deprecation messages to disallow. 53 | config.active_support.disallowed_deprecation_warnings = [] 54 | 55 | # Raises error for missing translations. 56 | # config.i18n.raise_on_missing_translations = true 57 | 58 | # Annotate rendered view with file names. 59 | # config.action_view.annotate_rendered_view_with_filenames = true 60 | end 61 | -------------------------------------------------------------------------------- /config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ActiveSupport::Reloader.to_prepare do 4 | # ApplicationController.renderer.defaults.merge!( 5 | # http_host: 'example.org', 6 | # https: false 7 | # ) 8 | # end 9 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = "1.0" 5 | 6 | # Add additional assets to the asset load path. 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in the app/assets 11 | # folder are already added. 12 | # Rails.application.config.assets.precompile += %w( admin.js admin.css ) 13 | 14 | # NOTE: avoid segmentation fault 15 | # https://github.com/sass/sassc-ruby/issues/207 16 | # https://github.com/rails/sprockets/issues/640 17 | Sprockets.export_concurrent = false 18 | -------------------------------------------------------------------------------- /config/initializers/avo.rb: -------------------------------------------------------------------------------- 1 | # For more information regaring these settings check out our docs https://docs.avohq.io 2 | Avo.configure do |config| 3 | ## == Routing == 4 | config.root_path = '/avo' 5 | 6 | # Where should the user be redirected when he hits the `/avo` url 7 | # config.home_path = nil 8 | 9 | ## == Licensing == 10 | config.license = 'community' # change this to 'pro' when you add the license key 11 | # config.license_key = ENV['AVO_LICENSE_KEY'] 12 | 13 | ## == Set the context == 14 | config.set_context do 15 | # Return a context object that gets evaluated in Avo::ApplicationController 16 | end 17 | 18 | ## == Authentication == 19 | # config.current_user_method = {} 20 | # config.authenticate_with = {} 21 | config.current_user_method do 22 | if session[:user_id] == "eip155:1:#{Rails.application.credentials.admin_user_wallet_id}" 23 | @current_user = session[:user_id] 24 | else 25 | flash[:notice] = "Hello '#{session[:user_id]}' !!!" 26 | redirect_to '/signin' 27 | end 28 | end 29 | 30 | ## == Authorization == 31 | # config.authorization_methods = { 32 | # index: 'index?', 33 | # show: 'show?', 34 | # edit: 'edit?', 35 | # new: 'new?', 36 | # update: 'update?', 37 | # create: 'create?', 38 | # destroy: 'destroy?', 39 | # } 40 | # config.raise_error_on_missing_policy = false 41 | 42 | ## == Localization == 43 | # config.locale = 'en-US' 44 | 45 | ## == Customization == 46 | # config.app_name = 'Avocadelicious' 47 | # config.timezone = 'UTC' 48 | # config.currency = 'USD' 49 | # config.per_page = 24 50 | # config.per_page_steps = [12, 24, 48, 72] 51 | # config.via_per_page = 8 52 | # config.default_view_type = :table 53 | # config.hide_layout_when_printing = false 54 | # config.id_links_to_resource = false 55 | # config.full_width_container = false 56 | # config.full_width_index_view = false 57 | # config.cache_resources_on_index_view = true 58 | # config.search_debounce = 300 59 | # config.view_component_path = "app/components" 60 | # config.display_license_request_timeout_error = true 61 | # config.disabled_features = [] 62 | 63 | 64 | ## == Breadcrumbs == 65 | # config.display_breadcrumbs = true 66 | # config.set_initial_breadcrumbs do 67 | # add_breadcrumb "Home", '/avo' 68 | # end 69 | 70 | ## == Menus == 71 | # config.main_menu = -> { 72 | # section "Dashboards", icon: "dashboards" do 73 | # all_dashboards 74 | # end 75 | 76 | # section "Resources", icon: "resources" do 77 | # all_resources 78 | # end 79 | 80 | # section "Tools", icon: "tools" do 81 | # all_tools 82 | # end 83 | # } 84 | # config.profile_menu = -> { 85 | # link "Profile", path: "/avo/profile", icon: "user-circle" 86 | # } 87 | end 88 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code 7 | # by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'". 8 | Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"] 9 | -------------------------------------------------------------------------------- /config/initializers/content_security_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide content security policy. 4 | # See the Securing Rails Applications Guide for more information: 5 | # https://guides.rubyonrails.org/security.html#content-security-policy-header 6 | 7 | # Rails.application.configure do 8 | # config.content_security_policy do |policy| 9 | # policy.default_src :self, :https 10 | # policy.font_src :self, :https, :data 11 | # policy.img_src :self, :https, :data 12 | # policy.object_src :none 13 | # policy.script_src :self, :https 14 | # policy.style_src :self, :https 15 | # # Specify URI for violation reports 16 | # # policy.report_uri "/csp-violation-report-endpoint" 17 | # end 18 | # 19 | # # Generate session nonces for permitted importmap and inline scripts 20 | # config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } 21 | # config.content_security_policy_nonce_directives = %w(script-src) 22 | # 23 | # # Report violations without enforcing the policy. 24 | # # config.content_security_policy_report_only = true 25 | # end 26 | -------------------------------------------------------------------------------- /config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [ 5 | :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn 6 | ] 7 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, "\\1en" 8 | # inflect.singular /^(ox)en/i, "\\1" 9 | # inflect.irregular "person", "people" 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym "RESTful" 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/meta_tags.rb: -------------------------------------------------------------------------------- 1 | MetaTags.configure do |c| 2 | c.title_limit = 70 3 | c.description_limit = 160 4 | c.keywords_limit = 255 5 | c.keywords_separator = ', ' 6 | end 7 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /config/initializers/omniauth.rb: -------------------------------------------------------------------------------- 1 | Rails.application.config.middleware.use OmniAuth::Builder do 2 | unless Rails.env.test? 3 | issuer = 'https://oidc.login.xyz/' 4 | client_options = { 5 | scheme: 'https', 6 | host: 'oidc.login.xyz', 7 | port: 443, 8 | authorization_endpoint: '/authorize', 9 | token_endpoint: '/token', 10 | userinfo_endpoint: '/userinfo', 11 | jwks_uri: 'https://oidc.login.xyz/jwk', 12 | identifier: Rails.application.credentials.dig(Rails.env.to_sym, :siwe_client_id), 13 | secret: Rails.application.credentials.dig(Rails.env.to_sym, :siwe_client_secret) 14 | } 15 | 16 | provider :siwe, issuer: issuer, client_options: client_options 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /config/initializers/permissions_policy.rb: -------------------------------------------------------------------------------- 1 | # Define an application-wide HTTP permissions policy. For further 2 | # information see https://developers.google.com/web/updates/2018/06/feature-policy 3 | # 4 | # Rails.application.config.permissions_policy do |f| 5 | # f.camera :none 6 | # f.gyroscope :none 7 | # f.microphone :none 8 | # f.usb :none 9 | # f.fullscreen :self 10 | # f.payment :self, "https://secure.example.com" 11 | # end 12 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_tdnm_session' 4 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /config/locales/avo.en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | avo: 3 | dashboard: 'Dashboard' 4 | dashboards: 'Dashboards' 5 | choose_a_country: 'Choose a country' 6 | choose_an_option: 'Choose an option' 7 | are_you_sure_you_want_to_run_this_option: 'Are you sure you want to run this action?' 8 | are_you_sure_detach_item: 'Are you sure you want to detach this %{item}.' 9 | run: 'Run' 10 | cancel: 'Cancel' 11 | action_ran_successfully: 'Action ran successfully!' 12 | details: "details" 13 | unauthorized: 'Unauthorized' 14 | attachment_class_attached: '%{attachment_class} attached.' 15 | attachment_class_detached: '%{attachment_class} detached.' 16 | resource_updated: 'Resource updated' 17 | resource_created: 'Resource created' 18 | resource_destroyed: 'Resource destroyed' 19 | switch_to_view: "Switch to %{view_type} view" 20 | click_to_reveal_filters: "Click to reveal filters" 21 | attachment_destroyed: 'Attachment destroyed' 22 | failed_to_find_attachment: 'Failed to find attachment' 23 | you_missed_something_check_form: 'You might have missed something. Please check the form.' 24 | remove_selection: 'Remove selection' 25 | select_item: 'Select item' 26 | select_all: 'Select all on page' 27 | delete_file: 'Delete file' 28 | delete: 'delete' 29 | delete_item: 'Delete %{item}' 30 | download_item: 'Download %{item}' 31 | download_file: 'Download file' 32 | download: 'Download' 33 | view: 'View' 34 | view_item: 'view %{item}' 35 | edit: 'edit' 36 | edit_item: 'edit %{item}' 37 | detach_item: 'detach %{item}' 38 | number_of_items: 39 | zero: 'no %{item}' 40 | one: 'one %{item}' 41 | other: '%{count} %{item}' 42 | are_you_sure: 'Are you sure?' 43 | filters: 'Filters' 44 | per_page: 'Per page' 45 | more: 'More' 46 | attach: 'Attach' 47 | cancel: 'Cancel' 48 | save: 'Save' 49 | attach_and_attach_another: 'Attach & Attach another' 50 | hide_content: 'Hide content' 51 | show_content: 'Show content' 52 | no_related_item_found: 'No related %{item} found' 53 | no_item_found: 'No %{item} found' 54 | loading: 'Loading' 55 | confirm: 'Confirm' 56 | actions: 'Actions' 57 | resources: 'Resources' 58 | oops_nothing_found: 'Oops! Nothing found...' 59 | type_to_search: 'Type to search.' 60 | and_x_other_resources: 'and %{count} other resources' 61 | go_back: 'Go back' 62 | home: 'Home' 63 | new: 'new' 64 | attach_item: 'Attach %{item}' 65 | choose_item: 'Choose %{item}' 66 | create_new_item: 'Create new %{item}' 67 | table_view: 'Table view' 68 | grid_view: 'Grid view' 69 | next_page: 'Next page' 70 | prev_page: 'Previous page' 71 | list_is_empty: 'List is empty' 72 | field_translations: 73 | file: 74 | zero: 'files' 75 | one: 'file' 76 | other: 'files' 77 | people: 78 | zero: 'peeps' 79 | one: 'peep' 80 | other: 'peeps' 81 | resource_translations: 82 | user: 83 | zero: 'users' 84 | one: 'user' 85 | other: 'users' 86 | reset_filters: 'Reset filters' 87 | not_authorized: 'You are not authorized to perform this action.' 88 | search: 89 | placeholder: 'Search' 90 | cancel_button: 'Cancel' 91 | sign_out: 'Sign out' 92 | failed: 'Failed' 93 | failed_to_load: 'Failed to load' 94 | key_value_field: 95 | key: 'Key' 96 | value: 'Value' 97 | add_row: 'Add row' 98 | delete_row: 'Delete row' 99 | was_successfully_created: 'was successfully created' 100 | was_successfully_updated: 'was successfully updated' 101 | clear_value: "Clear value" 102 | tools: Tools 103 | order: 104 | reorder_record: Reorder record 105 | higher: Move record higher 106 | lower: Move record lower 107 | to_top: Move record to top 108 | to_bottom: Move record to bottom 109 | empty_dashboard_message: Add cards to this dashboard 110 | no_cards_present: No cards present 111 | no_options_available: No options available 112 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # The following keys must be escaped otherwise they will not be retrieved by 20 | # the default I18n backend: 21 | # 22 | # true, false, on, off, yes, no 23 | # 24 | # Instead, surround them with single quotes. 25 | # 26 | # en: 27 | # 'true': 'foo' 28 | # 29 | # To learn more, please read the Rails Internationalization guide 30 | # available at https://guides.rubyonrails.org/i18n.html. 31 | 32 | en: 33 | hello: "Hello world" 34 | -------------------------------------------------------------------------------- /config/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers: a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum; this matches the default thread size of Active Record. 6 | # 7 | max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } 8 | min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } 9 | threads min_threads_count, max_threads_count 10 | 11 | # Specifies the `worker_timeout` threshold that Puma will use to wait before 12 | # terminating a worker in development environments. 13 | # 14 | worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" 15 | 16 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 17 | # 18 | port ENV.fetch("PORT") { 3000 } 19 | 20 | # Specifies the `environment` that Puma will run in. 21 | # 22 | environment ENV.fetch("RAILS_ENV") { "development" } 23 | 24 | # Specifies the `pidfile` that Puma will use. 25 | pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } 26 | 27 | # Specifies the number of `workers` to boot in clustered mode. 28 | # Workers are forked web server processes. If using threads and workers together 29 | # the concurrency of the application would be max `threads` * `workers`. 30 | # Workers do not work on JRuby or Windows (both of which do not support 31 | # processes). 32 | # 33 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 34 | 35 | # Use the `preload_app!` method when specifying a `workers` number. 36 | # This directive tells Puma to first boot the application and load code 37 | # before forking the application. This takes advantage of Copy On Write 38 | # process behavior so workers use less memory. 39 | # 40 | # preload_app! 41 | 42 | # Allow puma to be restarted by `rails restart` command. 43 | plugin :tmp_restart 44 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | mount Avo::Engine, at: Avo.configuration.root_path 3 | if Rails.env.development? 4 | mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql" 5 | end 6 | post "/graphql", to: "graphql#execute" 7 | 8 | root 'articles#index' 9 | 10 | get '/atom.xml', controller: 'articles', action: 'index', format: 'atom' 11 | get '/:year/:month/:day/:slug', to: 'articles#show', year: /\d{4}/, month: /\d{2}/, day: /\d{2}/ 12 | get '/blog/:year/:month/:day/:slug', to: redirect('/%{year}/%{month}/%{day}/%{slug}') 13 | 14 | get '/signin', to: 'sessions#new' 15 | get '/auth/:provider/callback', to: 'sessions#create' 16 | 17 | get '/:title', to: 'articles#show', as: :article 18 | end 19 | -------------------------------------------------------------------------------- /config/sitemap.rb: -------------------------------------------------------------------------------- 1 | SitemapGenerator::Sitemap.default_host = ENV['DEFAULT_HOST'] || "http://www.example.com" 2 | 3 | SitemapGenerator::Sitemap.create do 4 | Article.published.find_each do |a| 5 | d = a.published_on 6 | add( 7 | article_path(title: a.title), 8 | lastmod: a.updated_at 9 | ) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /config/spring.rb: -------------------------------------------------------------------------------- 1 | %w[ 2 | .ruby-version 3 | .rbenv-vars 4 | tmp/restart.txt 5 | tmp/caching-dev.txt 6 | ].each { |path| Spring.watch(path) } 7 | -------------------------------------------------------------------------------- /config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | 9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) 10 | # amazon: 11 | # service: S3 12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> 13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> 14 | # region: us-east-1 15 | # bucket: your_own_bucket 16 | 17 | # Remember not to checkin your GCS keyfile to a repository 18 | # google: 19 | # service: GCS 20 | # project: your_project 21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> 22 | # bucket: your_own_bucket 23 | 24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) 25 | # microsoft: 26 | # service: AzureStorage 27 | # storage_account_name: your_account_name 28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> 29 | # container: your_container_name 30 | 31 | # mirror: 32 | # service: Mirror 33 | # primary: local 34 | # mirrors: [ amazon, google, microsoft ] 35 | -------------------------------------------------------------------------------- /db/migrate/20150803141807_create_articles.rb: -------------------------------------------------------------------------------- 1 | class CreateArticles < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :articles do |t| 4 | t.string :title, null: false 5 | t.string :body, null: false 6 | t.string :url_title, null: false 7 | t.date :published_on 8 | t.timestamps null: false 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20150804044739_create_weblogs.rb: -------------------------------------------------------------------------------- 1 | class CreateWeblogs < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :weblogs do |t| 4 | t.string :title, null: false 5 | 6 | t.timestamps null: false 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20160110151755_change_column_article_body_to_text.rb: -------------------------------------------------------------------------------- 1 | class ChangeColumnArticleBodyToText < ActiveRecord::Migration[5.1] 2 | def change 3 | change_column :articles, :body, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20161023132949_add_draft_to_articles.rb: -------------------------------------------------------------------------------- 1 | class AddDraftToArticles < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :articles, :draft, :boolean, null: false, default: false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180326163716_add_default_eye_catching_image_url_to_weblog.rb: -------------------------------------------------------------------------------- 1 | class AddDefaultEyeCatchingImageUrlToWeblog < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :weblogs, :default_eye_catching_image_url, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180416143233_rename_url_title_to_slug_on_articles.rb: -------------------------------------------------------------------------------- 1 | class RenameUrlTitleToSlugOnArticles < ActiveRecord::Migration[5.1] 2 | def change 3 | rename_column :articles, :url_title, :slug 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180416150121_add_eye_catching_image_url_to_articles.rb: -------------------------------------------------------------------------------- 1 | class AddEyeCatchingImageUrlToArticles < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :articles, :eye_catching_image_url, :string, null: false, default: '' 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190604125626_change_articles_eyecatching_url_size.rb: -------------------------------------------------------------------------------- 1 | class ChangeArticlesEyecatchingUrlSize < ActiveRecord::Migration[5.2] 2 | def change 3 | change_column :articles, :eye_catching_image_url, :string, limit: 1024 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190924161405_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from active_storage (originally 20180723000244) 2 | class AddForeignKeyConstraintToActiveStorageAttachmentsForBlobId < ActiveRecord::Migration[6.0] 3 | def up 4 | return if foreign_key_exists?(:active_storage_attachments, column: :blob_id) 5 | 6 | if table_exists?(:active_storage_blobs) 7 | add_foreign_key :active_storage_attachments, :active_storage_blobs, column: :blob_id 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20200324153331_add_index_to_articles_published_on.rb: -------------------------------------------------------------------------------- 1 | class AddIndexToArticlesPublishedOn < ActiveRecord::Migration[6.0] 2 | def change 3 | add_index :articles, :published_on, name: :idx_published_on 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20210908153117_add_unique_index_to_article_title.rb: -------------------------------------------------------------------------------- 1 | class AddUniqueIndexToArticleTitle < ActiveRecord::Migration[6.1] 2 | def change 3 | add_index :articles, :title, unique: true 4 | end 5 | end 6 | 7 | -------------------------------------------------------------------------------- /db/migrate/20230303004038_rename_column_eye_catching_image_url_to_featured_imaeg_url.rb: -------------------------------------------------------------------------------- 1 | class RenameColumnEyeCatchingImageUrlToFeaturedImaegUrl < ActiveRecord::Migration[7.0] 2 | def change 3 | rename_column :articles, :eye_catching_image_url, :featured_image_url 4 | rename_column :weblogs, :default_eye_catching_image_url, :default_featured_image_url 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/schema.rb: -------------------------------------------------------------------------------- 1 | # This file is auto-generated from the current state of the database. Instead 2 | # of editing this file, please use the migrations feature of Active Record to 3 | # incrementally modify your database, and then regenerate this schema definition. 4 | # 5 | # This file is the source Rails uses to define your schema when running `bin/rails 6 | # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to 7 | # be faster and is potentially less error prone than running all of your 8 | # migrations from scratch. Old migrations may fail to apply correctly if those 9 | # migrations use external dependencies or application code. 10 | # 11 | # It's strongly recommended that you check this file into your version control system. 12 | 13 | ActiveRecord::Schema[7.0].define(version: 2023_03_03_004038) do 14 | # These are extensions that must be enabled in order to support this database 15 | enable_extension "plpgsql" 16 | 17 | create_table "articles", force: :cascade do |t| 18 | t.string "title", null: false 19 | t.text "body", null: false 20 | t.string "slug", null: false 21 | t.date "published_on" 22 | t.datetime "created_at", null: false 23 | t.datetime "updated_at", null: false 24 | t.boolean "draft", default: false, null: false 25 | t.string "featured_image_url", limit: 1024, default: "", null: false 26 | t.index ["published_on"], name: "idx_published_on" 27 | t.index ["title"], name: "index_articles_on_title", unique: true 28 | end 29 | 30 | create_table "weblogs", force: :cascade do |t| 31 | t.string "title", null: false 32 | t.datetime "created_at", null: false 33 | t.datetime "updated_at", null: false 34 | t.string "default_featured_image_url" 35 | end 36 | 37 | end 38 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }]) 7 | # Character.create(name: 'Luke', movie: movies.first) 8 | 9 | ApplicationRecord.transaction do 10 | 11 | weblog = Weblog.create!(title: 'My Weblog') 12 | 13 | Article.create!( 14 | title: 'My First Article', 15 | published_on: Date.today, 16 | slug: '01', 17 | body: <<~EOS, 18 | # Hello tdnm 19 | 20 | I'm fine! 21 | EOS 22 | ) 23 | end 24 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | https-portal: 5 | image: steveltn/https-portal:1 6 | ports: 7 | - '80:80' 8 | - '443:443' 9 | depends_on: 10 | - webapp 11 | environment: 12 | DOMAINS: 'tdnm.localhost -> http://webapp:3000' 13 | STAGE: 'local' 14 | 15 | webapp: 16 | build: 17 | context: . 18 | dockerfile: Dockerfile 19 | links: 20 | - db 21 | environment: 22 | - DATABASE_HOST=db 23 | - DATABASE_PASSWORD=postgres 24 | - DEFAULT_URL=https://tdnm.localhost 25 | - SELENIUM_HOST=selenium 26 | - SELENIUM_APP_HOST=webapp 27 | - TZ=Asia/Tokyo 28 | volumes: 29 | - .:/app 30 | - bundle_cache:/app/vendor/bundle 31 | command: ["wait-for-it", "db:5432", "--", "bash", "-c", "bin/setup; rm tmp/pids/server.pid 2>/dev/null; bin/rails s -b '0.0.0.0'"] 32 | 33 | db: 34 | image: postgres:14 35 | volumes: 36 | - pg_data:/var/lib/postgresql/data 37 | environment: 38 | - POSTGRES_PASSWORD=postgres 39 | 40 | selenium: 41 | image: selenium/standalone-firefox-debug 42 | 43 | volumes: 44 | pg_data: 45 | bundle_cache: 46 | -------------------------------------------------------------------------------- /lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/lib/assets/.keep -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/lib/tasks/.keep -------------------------------------------------------------------------------- /lib/tasks/import.thor: -------------------------------------------------------------------------------- 1 | require 'find' 2 | 3 | class TdnmCli < Thor 4 | desc 'import', 'import from middleman blog' 5 | def import(base_dir) 6 | require './config/environment' 7 | 8 | entries = Find.find("#{base_dir}/source").grep(/\d{4}-\d{2}-\d{2}-*/).map {|e| 9 | a = YAML.load_file(e) 10 | a["body"] = File.read(e).gsub(/---.+---\s+/m, '') 11 | a["url_title"] = e.match(/\d{4}-\d{2}-\d{2}-([^-].+?)\./)[1] 12 | a 13 | } 14 | 15 | Article.transaction do 16 | entries.each do |e| 17 | Article.create!( 18 | title: e["title"], 19 | url_title: e["url_title"], 20 | body: e["body"], 21 | published_on: e["date"] 22 | ) 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/tasks/rbs.rake: -------------------------------------------------------------------------------- 1 | require 'rbs_rails/rake_task' 2 | RbsRails::RakeTask.new 3 | -------------------------------------------------------------------------------- /log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/log/.keep -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | -------------------------------------------------------------------------------- /sig/rbs_rails/app/models/article.rbs: -------------------------------------------------------------------------------- 1 | class Article < ApplicationRecord 2 | extend _ActiveRecord_Relation_ClassMethods[Article, ActiveRecord_Relation, Integer] 3 | 4 | attr_accessor id(): Integer 5 | def id_changed?: () -> bool 6 | def id_change: () -> [ Integer?, Integer? ] 7 | def id_will_change!: () -> void 8 | def id_was: () -> Integer? 9 | def id_previously_changed?: () -> bool 10 | def id_previous_change: () -> Array[Integer?]? 11 | def id_previously_was: () -> Integer? 12 | def id_before_last_save: () -> Integer? 13 | def id_change_to_be_saved: () -> Array[Integer?]? 14 | def id_in_database: () -> Integer? 15 | def saved_change_to_id: () -> Array[Integer?]? 16 | def saved_change_to_id?: () -> bool 17 | def will_save_change_to_id?: () -> bool 18 | def restore_id!: () -> void 19 | def clear_id_change: () -> void 20 | 21 | attr_accessor title(): String 22 | def title_changed?: () -> bool 23 | def title_change: () -> [ String?, String? ] 24 | def title_will_change!: () -> void 25 | def title_was: () -> String? 26 | def title_previously_changed?: () -> bool 27 | def title_previous_change: () -> Array[String?]? 28 | def title_previously_was: () -> String? 29 | def title_before_last_save: () -> String? 30 | def title_change_to_be_saved: () -> Array[String?]? 31 | def title_in_database: () -> String? 32 | def saved_change_to_title: () -> Array[String?]? 33 | def saved_change_to_title?: () -> bool 34 | def will_save_change_to_title?: () -> bool 35 | def restore_title!: () -> void 36 | def clear_title_change: () -> void 37 | 38 | attr_accessor body(): String 39 | def body_changed?: () -> bool 40 | def body_change: () -> [ String?, String? ] 41 | def body_will_change!: () -> void 42 | def body_was: () -> String? 43 | def body_previously_changed?: () -> bool 44 | def body_previous_change: () -> Array[String?]? 45 | def body_previously_was: () -> String? 46 | def body_before_last_save: () -> String? 47 | def body_change_to_be_saved: () -> Array[String?]? 48 | def body_in_database: () -> String? 49 | def saved_change_to_body: () -> Array[String?]? 50 | def saved_change_to_body?: () -> bool 51 | def will_save_change_to_body?: () -> bool 52 | def restore_body!: () -> void 53 | def clear_body_change: () -> void 54 | 55 | attr_accessor slug(): String 56 | def slug_changed?: () -> bool 57 | def slug_change: () -> [ String?, String? ] 58 | def slug_will_change!: () -> void 59 | def slug_was: () -> String? 60 | def slug_previously_changed?: () -> bool 61 | def slug_previous_change: () -> Array[String?]? 62 | def slug_previously_was: () -> String? 63 | def slug_before_last_save: () -> String? 64 | def slug_change_to_be_saved: () -> Array[String?]? 65 | def slug_in_database: () -> String? 66 | def saved_change_to_slug: () -> Array[String?]? 67 | def saved_change_to_slug?: () -> bool 68 | def will_save_change_to_slug?: () -> bool 69 | def restore_slug!: () -> void 70 | def clear_slug_change: () -> void 71 | 72 | attr_accessor published_on(): Date? 73 | def published_on_changed?: () -> bool 74 | def published_on_change: () -> [ Date?, Date? ] 75 | def published_on_will_change!: () -> void 76 | def published_on_was: () -> Date? 77 | def published_on_previously_changed?: () -> bool 78 | def published_on_previous_change: () -> Array[Date?]? 79 | def published_on_previously_was: () -> Date? 80 | def published_on_before_last_save: () -> Date? 81 | def published_on_change_to_be_saved: () -> Array[Date?]? 82 | def published_on_in_database: () -> Date? 83 | def saved_change_to_published_on: () -> Array[Date?]? 84 | def saved_change_to_published_on?: () -> bool 85 | def will_save_change_to_published_on?: () -> bool 86 | def restore_published_on!: () -> void 87 | def clear_published_on_change: () -> void 88 | 89 | attr_accessor created_at(): ActiveSupport::TimeWithZone 90 | def created_at_changed?: () -> bool 91 | def created_at_change: () -> [ ActiveSupport::TimeWithZone?, ActiveSupport::TimeWithZone? ] 92 | def created_at_will_change!: () -> void 93 | def created_at_was: () -> ActiveSupport::TimeWithZone? 94 | def created_at_previously_changed?: () -> bool 95 | def created_at_previous_change: () -> Array[ActiveSupport::TimeWithZone?]? 96 | def created_at_previously_was: () -> ActiveSupport::TimeWithZone? 97 | def created_at_before_last_save: () -> ActiveSupport::TimeWithZone? 98 | def created_at_change_to_be_saved: () -> Array[ActiveSupport::TimeWithZone?]? 99 | def created_at_in_database: () -> ActiveSupport::TimeWithZone? 100 | def saved_change_to_created_at: () -> Array[ActiveSupport::TimeWithZone?]? 101 | def saved_change_to_created_at?: () -> bool 102 | def will_save_change_to_created_at?: () -> bool 103 | def restore_created_at!: () -> void 104 | def clear_created_at_change: () -> void 105 | 106 | attr_accessor updated_at(): ActiveSupport::TimeWithZone 107 | def updated_at_changed?: () -> bool 108 | def updated_at_change: () -> [ ActiveSupport::TimeWithZone?, ActiveSupport::TimeWithZone? ] 109 | def updated_at_will_change!: () -> void 110 | def updated_at_was: () -> ActiveSupport::TimeWithZone? 111 | def updated_at_previously_changed?: () -> bool 112 | def updated_at_previous_change: () -> Array[ActiveSupport::TimeWithZone?]? 113 | def updated_at_previously_was: () -> ActiveSupport::TimeWithZone? 114 | def updated_at_before_last_save: () -> ActiveSupport::TimeWithZone? 115 | def updated_at_change_to_be_saved: () -> Array[ActiveSupport::TimeWithZone?]? 116 | def updated_at_in_database: () -> ActiveSupport::TimeWithZone? 117 | def saved_change_to_updated_at: () -> Array[ActiveSupport::TimeWithZone?]? 118 | def saved_change_to_updated_at?: () -> bool 119 | def will_save_change_to_updated_at?: () -> bool 120 | def restore_updated_at!: () -> void 121 | def clear_updated_at_change: () -> void 122 | 123 | attr_accessor draft(): bool 124 | def draft_changed?: () -> bool 125 | def draft_change: () -> [ bool?, bool? ] 126 | def draft_will_change!: () -> void 127 | def draft_was: () -> bool? 128 | def draft_previously_changed?: () -> bool 129 | def draft_previous_change: () -> Array[bool?]? 130 | def draft_previously_was: () -> bool? 131 | def draft_before_last_save: () -> bool? 132 | def draft_change_to_be_saved: () -> Array[bool?]? 133 | def draft_in_database: () -> bool? 134 | def saved_change_to_draft: () -> Array[bool?]? 135 | def saved_change_to_draft?: () -> bool 136 | def will_save_change_to_draft?: () -> bool 137 | def restore_draft!: () -> void 138 | def clear_draft_change: () -> void 139 | attr_accessor draft?(): bool 140 | 141 | attr_accessor eye_catching_image_url(): String 142 | def eye_catching_image_url_changed?: () -> bool 143 | def eye_catching_image_url_change: () -> [ String?, String? ] 144 | def eye_catching_image_url_will_change!: () -> void 145 | def eye_catching_image_url_was: () -> String? 146 | def eye_catching_image_url_previously_changed?: () -> bool 147 | def eye_catching_image_url_previous_change: () -> Array[String?]? 148 | def eye_catching_image_url_previously_was: () -> String? 149 | def eye_catching_image_url_before_last_save: () -> String? 150 | def eye_catching_image_url_change_to_be_saved: () -> Array[String?]? 151 | def eye_catching_image_url_in_database: () -> String? 152 | def saved_change_to_eye_catching_image_url: () -> Array[String?]? 153 | def saved_change_to_eye_catching_image_url?: () -> bool 154 | def will_save_change_to_eye_catching_image_url?: () -> bool 155 | def restore_eye_catching_image_url!: () -> void 156 | def clear_eye_catching_image_url_change: () -> void 157 | 158 | def self.published: () -> ActiveRecord_Relation 159 | def self.drafts: () -> ActiveRecord_Relation 160 | 161 | class ActiveRecord_Relation < ActiveRecord::Relation 162 | include _ActiveRecord_Relation[Article, Integer] 163 | include Enumerable[Article] 164 | 165 | def published: () -> ActiveRecord_Relation 166 | def drafts: () -> ActiveRecord_Relation 167 | end 168 | 169 | class ActiveRecord_Associations_CollectionProxy < ActiveRecord::Associations::CollectionProxy 170 | end 171 | end 172 | -------------------------------------------------------------------------------- /sig/rbs_rails/app/models/weblog.rbs: -------------------------------------------------------------------------------- 1 | class Weblog < ApplicationRecord 2 | extend _ActiveRecord_Relation_ClassMethods[Weblog, ActiveRecord_Relation, Integer] 3 | 4 | attr_accessor id(): Integer 5 | def id_changed?: () -> bool 6 | def id_change: () -> [ Integer?, Integer? ] 7 | def id_will_change!: () -> void 8 | def id_was: () -> Integer? 9 | def id_previously_changed?: () -> bool 10 | def id_previous_change: () -> Array[Integer?]? 11 | def id_previously_was: () -> Integer? 12 | def id_before_last_save: () -> Integer? 13 | def id_change_to_be_saved: () -> Array[Integer?]? 14 | def id_in_database: () -> Integer? 15 | def saved_change_to_id: () -> Array[Integer?]? 16 | def saved_change_to_id?: () -> bool 17 | def will_save_change_to_id?: () -> bool 18 | def restore_id!: () -> void 19 | def clear_id_change: () -> void 20 | 21 | attr_accessor title(): String 22 | def title_changed?: () -> bool 23 | def title_change: () -> [ String?, String? ] 24 | def title_will_change!: () -> void 25 | def title_was: () -> String? 26 | def title_previously_changed?: () -> bool 27 | def title_previous_change: () -> Array[String?]? 28 | def title_previously_was: () -> String? 29 | def title_before_last_save: () -> String? 30 | def title_change_to_be_saved: () -> Array[String?]? 31 | def title_in_database: () -> String? 32 | def saved_change_to_title: () -> Array[String?]? 33 | def saved_change_to_title?: () -> bool 34 | def will_save_change_to_title?: () -> bool 35 | def restore_title!: () -> void 36 | def clear_title_change: () -> void 37 | 38 | attr_accessor created_at(): ActiveSupport::TimeWithZone 39 | def created_at_changed?: () -> bool 40 | def created_at_change: () -> [ ActiveSupport::TimeWithZone?, ActiveSupport::TimeWithZone? ] 41 | def created_at_will_change!: () -> void 42 | def created_at_was: () -> ActiveSupport::TimeWithZone? 43 | def created_at_previously_changed?: () -> bool 44 | def created_at_previous_change: () -> Array[ActiveSupport::TimeWithZone?]? 45 | def created_at_previously_was: () -> ActiveSupport::TimeWithZone? 46 | def created_at_before_last_save: () -> ActiveSupport::TimeWithZone? 47 | def created_at_change_to_be_saved: () -> Array[ActiveSupport::TimeWithZone?]? 48 | def created_at_in_database: () -> ActiveSupport::TimeWithZone? 49 | def saved_change_to_created_at: () -> Array[ActiveSupport::TimeWithZone?]? 50 | def saved_change_to_created_at?: () -> bool 51 | def will_save_change_to_created_at?: () -> bool 52 | def restore_created_at!: () -> void 53 | def clear_created_at_change: () -> void 54 | 55 | attr_accessor updated_at(): ActiveSupport::TimeWithZone 56 | def updated_at_changed?: () -> bool 57 | def updated_at_change: () -> [ ActiveSupport::TimeWithZone?, ActiveSupport::TimeWithZone? ] 58 | def updated_at_will_change!: () -> void 59 | def updated_at_was: () -> ActiveSupport::TimeWithZone? 60 | def updated_at_previously_changed?: () -> bool 61 | def updated_at_previous_change: () -> Array[ActiveSupport::TimeWithZone?]? 62 | def updated_at_previously_was: () -> ActiveSupport::TimeWithZone? 63 | def updated_at_before_last_save: () -> ActiveSupport::TimeWithZone? 64 | def updated_at_change_to_be_saved: () -> Array[ActiveSupport::TimeWithZone?]? 65 | def updated_at_in_database: () -> ActiveSupport::TimeWithZone? 66 | def saved_change_to_updated_at: () -> Array[ActiveSupport::TimeWithZone?]? 67 | def saved_change_to_updated_at?: () -> bool 68 | def will_save_change_to_updated_at?: () -> bool 69 | def restore_updated_at!: () -> void 70 | def clear_updated_at_change: () -> void 71 | 72 | attr_accessor default_eye_catching_image_url(): String? 73 | def default_eye_catching_image_url_changed?: () -> bool 74 | def default_eye_catching_image_url_change: () -> [ String?, String? ] 75 | def default_eye_catching_image_url_will_change!: () -> void 76 | def default_eye_catching_image_url_was: () -> String? 77 | def default_eye_catching_image_url_previously_changed?: () -> bool 78 | def default_eye_catching_image_url_previous_change: () -> Array[String?]? 79 | def default_eye_catching_image_url_previously_was: () -> String? 80 | def default_eye_catching_image_url_before_last_save: () -> String? 81 | def default_eye_catching_image_url_change_to_be_saved: () -> Array[String?]? 82 | def default_eye_catching_image_url_in_database: () -> String? 83 | def saved_change_to_default_eye_catching_image_url: () -> Array[String?]? 84 | def saved_change_to_default_eye_catching_image_url?: () -> bool 85 | def will_save_change_to_default_eye_catching_image_url?: () -> bool 86 | def restore_default_eye_catching_image_url!: () -> void 87 | def clear_default_eye_catching_image_url_change: () -> void 88 | 89 | class ActiveRecord_Relation < ActiveRecord::Relation 90 | include _ActiveRecord_Relation[Weblog, Integer] 91 | include Enumerable[Weblog] 92 | end 93 | 94 | class ActiveRecord_Associations_CollectionProxy < ActiveRecord::Associations::CollectionProxy 95 | end 96 | end 97 | -------------------------------------------------------------------------------- /sig/rbs_rails/model_dependencies.rbs: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | end 3 | -------------------------------------------------------------------------------- /sig/rbs_rails/path_helpers.rbs: -------------------------------------------------------------------------------- 1 | interface _RbsRailsPathHelpers 2 | def rails_info_properties_path: (*untyped) -> String 3 | def rails_info_routes_path: (*untyped) -> String 4 | def rails_info_path: (*untyped) -> String 5 | def rails_mailers_path: (*untyped) -> String 6 | def graphiql_rails_path: (*untyped) -> String 7 | def graphql_path: (*untyped) -> String 8 | def admin_articles_path: (*untyped) -> String 9 | def new_admin_article_path: (*untyped) -> String 10 | def edit_admin_article_path: (*untyped) -> String 11 | def admin_article_path: (*untyped) -> String 12 | def admin_weblogs_path: (*untyped) -> String 13 | def new_admin_weblog_path: (*untyped) -> String 14 | def edit_admin_weblog_path: (*untyped) -> String 15 | def admin_weblog_path: (*untyped) -> String 16 | def admin_root_path: (*untyped) -> String 17 | def root_path: (*untyped) -> String 18 | def amp_path: (*untyped) -> String 19 | def article_path: (*untyped) -> String 20 | def turbo_recede_historical_location_path: (*untyped) -> String 21 | def turbo_resume_historical_location_path: (*untyped) -> String 22 | def turbo_refresh_historical_location_path: (*untyped) -> String 23 | def rails_postmark_inbound_emails_path: (*untyped) -> String 24 | def rails_relay_inbound_emails_path: (*untyped) -> String 25 | def rails_sendgrid_inbound_emails_path: (*untyped) -> String 26 | def rails_mandrill_inbound_health_check_path: (*untyped) -> String 27 | def rails_mandrill_inbound_emails_path: (*untyped) -> String 28 | def rails_mailgun_inbound_emails_path: (*untyped) -> String 29 | def rails_conductor_inbound_emails_path: (*untyped) -> String 30 | def new_rails_conductor_inbound_email_path: (*untyped) -> String 31 | def edit_rails_conductor_inbound_email_path: (*untyped) -> String 32 | def rails_conductor_inbound_email_path: (*untyped) -> String 33 | def new_rails_conductor_inbound_email_source_path: (*untyped) -> String 34 | def rails_conductor_inbound_email_sources_path: (*untyped) -> String 35 | def rails_conductor_inbound_email_reroute_path: (*untyped) -> String 36 | def rails_service_blob_path: (*untyped) -> String 37 | def rails_service_blob_proxy_path: (*untyped) -> String 38 | def rails_blob_representation_path: (*untyped) -> String 39 | def rails_blob_representation_proxy_path: (*untyped) -> String 40 | def rails_disk_service_path: (*untyped) -> String 41 | def update_rails_disk_service_path: (*untyped) -> String 42 | def rails_direct_uploads_path: (*untyped) -> String 43 | def rails_representation_path: (*untyped) -> String 44 | def rails_blob_path: (*untyped) -> String 45 | def rails_storage_proxy_path: (*untyped) -> String 46 | def rails_storage_redirect_path: (*untyped) -> String 47 | def rails_info_properties_url: (*untyped) -> String 48 | def rails_info_routes_url: (*untyped) -> String 49 | def rails_info_url: (*untyped) -> String 50 | def rails_mailers_url: (*untyped) -> String 51 | def graphiql_rails_url: (*untyped) -> String 52 | def graphql_url: (*untyped) -> String 53 | def admin_articles_url: (*untyped) -> String 54 | def new_admin_article_url: (*untyped) -> String 55 | def edit_admin_article_url: (*untyped) -> String 56 | def admin_article_url: (*untyped) -> String 57 | def admin_weblogs_url: (*untyped) -> String 58 | def new_admin_weblog_url: (*untyped) -> String 59 | def edit_admin_weblog_url: (*untyped) -> String 60 | def admin_weblog_url: (*untyped) -> String 61 | def admin_root_url: (*untyped) -> String 62 | def root_url: (*untyped) -> String 63 | def amp_url: (*untyped) -> String 64 | def article_url: (*untyped) -> String 65 | def turbo_recede_historical_location_url: (*untyped) -> String 66 | def turbo_resume_historical_location_url: (*untyped) -> String 67 | def turbo_refresh_historical_location_url: (*untyped) -> String 68 | def rails_postmark_inbound_emails_url: (*untyped) -> String 69 | def rails_relay_inbound_emails_url: (*untyped) -> String 70 | def rails_sendgrid_inbound_emails_url: (*untyped) -> String 71 | def rails_mandrill_inbound_health_check_url: (*untyped) -> String 72 | def rails_mandrill_inbound_emails_url: (*untyped) -> String 73 | def rails_mailgun_inbound_emails_url: (*untyped) -> String 74 | def rails_conductor_inbound_emails_url: (*untyped) -> String 75 | def new_rails_conductor_inbound_email_url: (*untyped) -> String 76 | def edit_rails_conductor_inbound_email_url: (*untyped) -> String 77 | def rails_conductor_inbound_email_url: (*untyped) -> String 78 | def new_rails_conductor_inbound_email_source_url: (*untyped) -> String 79 | def rails_conductor_inbound_email_sources_url: (*untyped) -> String 80 | def rails_conductor_inbound_email_reroute_url: (*untyped) -> String 81 | def rails_service_blob_url: (*untyped) -> String 82 | def rails_service_blob_proxy_url: (*untyped) -> String 83 | def rails_blob_representation_url: (*untyped) -> String 84 | def rails_blob_representation_proxy_url: (*untyped) -> String 85 | def rails_disk_service_url: (*untyped) -> String 86 | def update_rails_disk_service_url: (*untyped) -> String 87 | def rails_direct_uploads_url: (*untyped) -> String 88 | def rails_representation_url: (*untyped) -> String 89 | def rails_blob_url: (*untyped) -> String 90 | def rails_storage_proxy_url: (*untyped) -> String 91 | def rails_storage_redirect_url: (*untyped) -> String 92 | end 93 | -------------------------------------------------------------------------------- /test/application_system_test_case.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class ApplicationSystemTestCase < ActionDispatch::SystemTestCase 4 | driven_by Capybara.default_driver 5 | end 6 | -------------------------------------------------------------------------------- /test/controllers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/test/controllers/.keep -------------------------------------------------------------------------------- /test/controllers/articles_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ArticlesControllerTest < ActionController::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /test/fixtures/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/test/fixtures/.keep -------------------------------------------------------------------------------- /test/fixtures/articles.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/test/fixtures/articles.yml -------------------------------------------------------------------------------- /test/fixtures/weblogs.yml: -------------------------------------------------------------------------------- 1 | my_weblog: 2 | id: 1 3 | title: 'tdnm app' 4 | -------------------------------------------------------------------------------- /test/helpers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/test/helpers/.keep -------------------------------------------------------------------------------- /test/integration/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/test/integration/.keep -------------------------------------------------------------------------------- /test/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/test/mailers/.keep -------------------------------------------------------------------------------- /test/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/test/models/.keep -------------------------------------------------------------------------------- /test/models/article_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ArticleTest < ActiveSupport::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /test/models/weblog_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class WeblogTest < ActiveSupport::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /test/system/articles_test.rb: -------------------------------------------------------------------------------- 1 | require "application_system_test_case" 2 | 3 | class ArticlesTest < ApplicationSystemTestCase 4 | test "viewing the index" do 5 | visit root_path 6 | assert_selector "header", text: "tdnm app" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../config/environment', __FILE__) 2 | require 'rails/test_help' 3 | 4 | class ActiveSupport::TestCase 5 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. 6 | fixtures :all 7 | 8 | # Add more helper methods to be used by all tests here... 9 | end 10 | 11 | Capybara.register_driver :selenium_remote_firefox do |app| 12 | Capybara::Selenium::Driver.new( 13 | app, 14 | browser: :remote, 15 | url: "http://#{ENV['SELENIUM_HOST'] || 'localhost' }:4444/wd/hub", 16 | desired_capabilities: Selenium::WebDriver::Remote::Capabilities.firefox 17 | ) 18 | end 19 | 20 | Capybara.default_driver = ENV['CI'] ? :selenium_headless : :selenium_remote_firefox 21 | 22 | if ENV['SELENIUM_APP_HOST'] 23 | Capybara.server_host = ENV['SELENIUM_APP_HOST'] 24 | end 25 | -------------------------------------------------------------------------------- /tmp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenchan/tdnm_blog/2aa48ea6eaff17758f5477a8a638671e94275fae/tmp/.keep --------------------------------------------------------------------------------